1 #ifndef UTIL___RANGE_COLL__HPP
2 #define UTIL___RANGE_COLL__HPP
3 
4 /*  $Id: range_coll.hpp 601340 2020-02-05 20:26:06Z vasilche $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Authors:  Andrey Yazhuk
30  *
31  * File Description:
32  *  class CRangeCollection - sorted collection of non-overlapping CRange-s
33  */
34 
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbistl.hpp>
37 
38 #include <util/range.hpp>
39 
40 #include <algorithm>
41 
42 BEGIN_NCBI_SCOPE
43 
44 template<class Range, class Position>
45 struct PRangeLessPos
46 {
47     using is_transparent = void;
operator ()PRangeLessPos48     bool operator()(const Range &R, Position Pos)     { return R.GetToOpen() <= Pos;  }
49     //bool operator()(Position Pos, const Range &R)     { return Pos < R.GetToOpen();  }
operator ()PRangeLessPos50     bool operator()(const Range &R1, const Range &R2) { return R1.GetToOpen() < R2.GetToOpen();  }
51 };
52 
53 ///////////////////////////////////////////////////////////////////////////////
54 // class CRangeCollection<Position> represent a sorted collection of
55 // CRange<Position>. It is guaranteed that ranges in collection do not overlap.
56 // Unless DivideAt() was explicitly called, it is also guarantees that they
57 // aren't adjacent so that there is no gap beween them.
58 // Adding an interval to the collection leads to possible merging it with
59 // existing intervals.
60 
61 template<class Position>
62 class CRangeCollection
63 {
64 public:
65     typedef Position    position_type;
66     typedef CRangeCollection<position_type>  TThisType;
67 
68     typedef CRange<position_type>    TRange;
69     typedef vector<TRange>      TRangeVector;
70     typedef typename TRangeVector::const_iterator    const_iterator;
71     typedef typename TRangeVector::const_reverse_iterator    const_reverse_iterator;
72     typedef typename TRangeVector::size_type size_type;
73 
CRangeCollection()74     CRangeCollection()   { }
CRangeCollection(const TRange & r)75     explicit CRangeCollection(const TRange& r)
76     {
77         m_vRanges.push_back(r);
78     }
CRangeCollection(const CRangeCollection & c)79     CRangeCollection(const CRangeCollection &c)
80     {
81         m_vRanges = c.m_vRanges;
82     }
83 
84     // immitating vector, but providing only "const" access to elements
begin() const85     const_iterator  begin() const
86     {
87         return m_vRanges.begin();
88     }
end() const89     const_iterator  end() const
90     {
91         return m_vRanges.end();
92     }
rbegin() const93     const_reverse_iterator  rbegin() const
94     {
95         return m_vRanges.rbegin();
96     }
rend() const97     const_reverse_iterator  rend() const
98     {
99         return m_vRanges.rend();
100     }
size() const101     size_type size() const
102     {
103         return m_vRanges.size();
104     }
empty() const105     bool    empty() const
106     {
107         return m_vRanges.empty();
108     }
operator [](size_type pos) const109     const   TRange& operator[](size_type pos)   const
110     {
111         return m_vRanges[pos];
112     }
clear()113     void    clear()
114     {
115         m_vRanges.clear();
116     }
117     // returns iterator pointing to the TRange that has ToOpen > pos
find(position_type pos) const118     const_iterator  find(position_type pos)   const
119     {
120         PRangeLessPos<TRange, position_type> p;
121         return lower_bound(begin(), end(), pos, p);
122     }
GetFrom() const123     position_type   GetFrom() const
124     {
125         if(! m_vRanges.empty())
126             return begin()->GetFrom();
127         else return TRange::GetEmptyFrom();
128     }
GetToOpen() const129     position_type   GetToOpen() const
130     {
131         if(! m_vRanges.empty())
132             return rbegin()->GetToOpen();
133         else return TRange::GetEmptyToOpen();
134     }
GetTo() const135     position_type   GetTo() const
136     {
137         if(! m_vRanges.empty())
138             return rbegin()->GetTo();
139         else return TRange::GetEmptyTo();
140     }
Empty() const141     bool            Empty() const
142     {
143         return empty();
144     }
NotEmpty() const145     bool            NotEmpty() const
146     {
147         return ! empty();
148     }
GetLength(void) const149     position_type   GetLength (void) const
150     {
151        if(! m_vRanges.empty())  {
152             position_type From = begin()->GetFrom();
153             return rbegin()->GetToOpen() - From;
154        } else return 0;
155     }
156     ///
157     /// Returns total length covered by ranges in this collection, i.e.
158     /// sum of lengths of ranges
159     ///
GetCoveredLength(void) const160     position_type   GetCoveredLength (void) const
161     {
162         position_type length = 0;
163         ITERATE(typename TThisType, it, m_vRanges)   {
164             length += it->GetLength();
165         }
166         return length;
167     }
GetLimits() const168     TRange          GetLimits() const
169     {
170         if(! m_vRanges.empty())  {
171             position_type From = begin()->GetFrom();
172             position_type To = rbegin()->GetTo();
173             return TRange(From, To);
174         } else return TRange::GetEmpty();
175     }
IntersectWith(const TRange & r)176     TThisType&  IntersectWith (const TRange& r)
177     {
178          x_IntersectWith(r);
179          return *this;
180     }
operator &=(const TRange & r)181     TThisType &  operator &= (const TRange& r)
182     {
183          x_IntersectWith(r);
184          return *this;
185     }
operator ==(const TThisType & c) const186     bool    operator == (const TThisType& c) const
187     {
188          return x_Equals(c);
189     }
IntersectingWith(const TRange & r) const190     bool  IntersectingWith (const TRange& r) const
191     {
192         return x_Intersects(r).second;
193     }
Contains(const TRange & r) const194     bool  Contains (const TRange& r) const
195     {
196         return x_Contains(r).second;
197     }
CombineWith(const TRange & r)198     TThisType&  CombineWith (const TRange& r)
199     {
200         x_CombineWith(r);
201         return *this;
202     }
operator +=(const TRange & r)203     TThisType &  operator+= (const TRange& r)
204     {
205         x_CombineWith(r);
206         return *this;
207     }
Subtract(const TRange & r)208     TThisType&  Subtract(const TRange& r)
209     {
210         x_Subtract(r);
211         return *this;
212     }
operator -=(const TRange & r)213     TThisType &  operator-= (const TRange& r)
214     {
215        x_Subtract(r);
216        return *this;
217     }
IntersectWith(const TThisType & c)218     TThisType&  IntersectWith (const TThisType &c)
219     {
220         x_IntersectWith(c);
221         return *this;
222     }
operator &=(const TThisType & c)223     TThisType &  operator&= (const TThisType &c)
224     {
225         x_IntersectWith(c);
226         return *this;
227     }
CombineWith(const TThisType & c)228     TThisType&  CombineWith (const TThisType &c)
229     {
230         x_CombineWith(c);
231         return *this;
232     }
operator +=(const TThisType & c)233     TThisType &  operator+= (const TThisType &c)
234     {
235         x_CombineWith(c);
236         return *this;
237     }
Subtract(const TThisType & c)238     TThisType&  Subtract(const TThisType &c)
239     {
240         x_Subtract(c);
241         return *this;
242     }
operator -=(const TThisType & c)243     TThisType &  operator-= (const TThisType &c)
244     {
245        x_Subtract(c);
246        return *this;
247     }
248 
249     /// If position is in middle of range, divide into two consecutive ranges
250     /// after this position
DivideAfter(const position_type & p)251     TThisType & DivideAfter(const position_type &p)
252     {
253        x_Divide(p);
254        return *this;
255     }
256 
257 protected:
258     typedef typename TRangeVector::iterator    iterator;
259     typedef typename TRangeVector::reverse_iterator    reverse_iterator;
260 
begin_nc()261     iterator  begin_nc()
262     {
263         return m_vRanges.begin();
264     }
end_nc()265     iterator  end_nc()
266     {
267         return m_vRanges.end();
268     }
find_nc(position_type pos)269     iterator find_nc(position_type pos) {
270         PRangeLessPos<TRange, position_type> p;
271         return lower_bound(begin_nc(), end_nc(), pos, p);
272     }
x_Find(position_type pos) const273     pair<const_iterator, bool>    x_Find(position_type pos) const
274     {
275         PRangeLessPos<TRange, position_type>    p;
276         const_iterator it = lower_bound(begin(), end(), pos, p);
277         bool b_contains = it != end()  &&  it->GetFrom() >= pos;
278         return make_pair(it, b_contains);
279     }
x_Intersects(const TRange & r) const280     pair<const_iterator, bool>    x_Intersects(const TRange& r) const
281     {
282         PRangeLessPos<TRange, position_type>    p;
283         const_iterator it = lower_bound(begin(), end(), r.GetFrom(), p);
284         bool b_intersects = it != end()  &&  it->GetFrom() < r.GetToOpen();
285         return make_pair(it, b_intersects);
286     }
x_Contains(const TRange & r) const287     pair<const_iterator, bool>    x_Contains(const TRange& r) const
288     {
289         PRangeLessPos<TRange, position_type>    p;
290         const_iterator it = lower_bound(begin(), end(), r.GetFrom(), p);
291         bool contains = false;
292         if (it != end()) {
293             contains = (it->GetFrom() <= r.GetFrom()  &&
294                         it->GetTo()   >= r.GetTo());
295         }
296         return make_pair(it, contains);
297     }
298 
x_IntersectWith(const TRange & r)299     void    x_IntersectWith(const TRange& r)
300     {
301         PRangeLessPos<TRange, position_type>    p;
302 
303         position_type pos_to = r.GetTo();
304         iterator it_right = lower_bound(begin_nc(), end_nc(), pos_to, p);
305         if(it_right != end_nc()) {
306             if(it_right->GetFrom() <= pos_to) {   //intersects
307                 it_right->SetTo(pos_to);
308                 ++it_right; // exclude from removal
309             }
310             m_vRanges.erase(it_right, end_nc()); // erase ranges to the right
311         }
312 
313         position_type pos_from = r.GetFrom();
314         iterator it_left =
315             lower_bound(begin_nc(), end_nc(), pos_from, p);
316         if(it_left != end_nc()) {
317             if(it_left->GetFrom() < pos_from)
318                 it_left->SetFrom(pos_from);
319         }
320         m_vRanges.erase(begin_nc(), it_left); //erase ranges to the left
321     }
322 
323     // returns iterator to the range representing result of combination
x_CombineWith(const TRange & r)324     iterator    x_CombineWith(const TRange& r)
325     {
326         PRangeLessPos<TRange, position_type>    p;
327 
328         position_type pos_from = r.GetFrom();
329         position_type pos_to_open = r.GetToOpen();
330 
331         if (pos_from == TRange::GetWholeFrom()) {
332             pos_from++; // Prevent overflow
333         }
334         iterator it_begin_m =
335             lower_bound(begin_nc(), end_nc(), pos_from - 1, p); /* NCBI_FAKE_WARNING: WorkShop */
336         if(it_begin_m != end_nc() && it_begin_m->GetFrom() <= pos_to_open)  { // intersection
337             iterator it_end_m = lower_bound(it_begin_m, end_nc(), pos_to_open, p);
338             it_begin_m->CombineWith(r);
339 
340             if(it_end_m != end_nc()  &&  it_end_m->GetFrom() <= pos_to_open) {// subject to merge
341                 it_begin_m->SetToOpen(it_end_m->GetToOpen());
342                 ++it_end_m; // including it into erased set
343             }
344             m_vRanges.erase(it_begin_m + 1, it_end_m);
345         } else {
346             m_vRanges.insert(it_begin_m, r);
347         }
348         return it_begin_m;
349     }
350 
x_Subtract(const TRange & r)351     void    x_Subtract(const TRange& r)
352     {
353         PRangeLessPos<TRange, position_type>    P;
354 
355         position_type pos_from = r.GetFrom();
356         position_type pos_to_open = r.GetToOpen();
357 
358         iterator it_begin_e = lower_bound(begin_nc(), end_nc(), pos_from, P);
359         if(it_begin_e != end_nc()) {   // possible intersection
360 
361             if(it_begin_e->GetFrom() < pos_from  &&  it_begin_e->GetToOpen() > pos_to_open)    {
362                 //it_begin_e contains R, split it in two
363                 TRange it_r = *it_begin_e;
364                 it_begin_e = m_vRanges.insert(it_begin_e, it_r);
365                 it_begin_e->SetToOpen(pos_from);
366                 (++it_begin_e)->SetFrom(pos_to_open);
367             } else  {
368                 if(it_begin_e->GetFrom() < pos_from) { // cut this segement , but don't erase
369                     it_begin_e->SetToOpen(pos_from);
370                     ++it_begin_e;
371                 }
372                 iterator it_end_e = lower_bound(it_begin_e, end_nc(), pos_to_open, P);
373                 if(it_end_e != end_nc()  &&  it_end_e->GetFrom() < pos_to_open)    {
374                     it_end_e->SetFrom(pos_to_open); // truncate
375                 }
376                 // erase ranges fully covered by R
377                 m_vRanges.erase(it_begin_e, it_end_e);
378             }
379         }
380     }
x_IntersectWith(const TThisType & c)381     void    x_IntersectWith(const TThisType &c)
382     {
383         TRangeVector intersection_ranges;
384         const_iterator my_iterator = begin(),
385                        c_iterator = c.begin();
386         while(my_iterator != end() && c_iterator != c.end())
387         {
388         TRange intersection = my_iterator->IntersectionWith(*c_iterator);
389             if(intersection.NotEmpty())
390                 intersection_ranges.push_back(intersection);
391             if(my_iterator->GetTo() < c_iterator->GetTo())
392                 ++my_iterator;
393             else
394                 ++c_iterator;
395         }
396         m_vRanges = intersection_ranges;
397     }
398 
x_Divide(const position_type & p)399     void    x_Divide(const position_type& p)
400     {
401         PRangeLessPos<TRange, position_type>    P;
402         iterator it = lower_bound(begin_nc(), end_nc(), p, P);
403         if (it != end_nc() && it->GetFrom() <= p && it->GetTo() > p) {
404             position_type end_pos = it->GetTo();
405             it->SetTo(p);
406             m_vRanges.insert(++it, TRange(p+1, end_pos));
407         }
408     }
409 
x_CombineWith(const TThisType & c)410     void    x_CombineWith(const TThisType &c)
411     {
412         ITERATE(typename TThisType, it, c)   {
413             x_CombineWith(*it);
414         }
415     }
x_Subtract(const TThisType & c)416     void    x_Subtract(const TThisType &c)
417     {
418         ITERATE(typename TThisType, it, c)   {
419             x_Subtract(*it);
420         }
421     }
x_Equals(const TThisType & c) const422     bool    x_Equals(const TThisType &c) const
423     {
424         if(&c == this)  {
425             return true;
426         } else {
427             return m_vRanges == c.m_vRanges;
428         }
429     }
430 
431 protected:
432     TRangeVector    m_vRanges;
433 };
434 
435 END_NCBI_SCOPE
436 
437 #endif  // UTIL___RANGE_COLL__HPP
438