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