1 /**
2 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 * storing and accessing finite element mesh data.
4 *
5 * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 * retains certain rights in this software.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 */
15
16 /****************************************************
17 * File : Range.cpp
18 *
19 * Purpose : Stores contiguous or partially
20 * contiguous values in an optimized
21 * fashion. Partially contiguous
22 * accessing patterns is also optimized.
23 *
24 * Creator : Clinton Stimpson
25 *
26 * Date : 15 April 2002
27 *
28 *******************************************************/
29
30
31 #include <assert.h>
32 #include "moab/Range.hpp"
33 #include "Internals.hpp"
34 #include "moab/CN.hpp"
35 #include <iostream>
36 #include <sstream>
37 #include <string>
38
39 #ifdef HAVE_BOOST_POOL_SINGLETON_POOL_HPP
40 # include <boost/pool/singleton_pool.hpp>
41 typedef boost::singleton_pool< moab::Range::PairNode , sizeof(moab::Range::PairNode) >
42 PairAlloc;
43 // static inline moab::Range::PairNode* alloc_pair()
44 // { return new (PairAlloc::malloc()) moab::Range::PairNode; }
alloc_pair(moab::Range::PairNode * n,moab::Range::PairNode * p,moab::EntityHandle f,moab::EntityHandle s)45 static inline moab::Range::PairNode* alloc_pair(moab::Range::PairNode* n, moab::Range::PairNode* p, moab::EntityHandle f, moab::EntityHandle s)
46 { return new (PairAlloc::malloc()) moab::Range::PairNode(n,p,f,s); }
free_pair(moab::Range::PairNode * node)47 static inline void free_pair( moab::Range::PairNode* node )
48 { node->~PairNode(); PairAlloc::free( node ); }
49 #else
50 // static inline moab::Range::PairNode* alloc_pair()
51 // { return new moab::Range::PairNode; }
alloc_pair(moab::Range::PairNode * n,moab::Range::PairNode * p,moab::EntityHandle f,moab::EntityHandle s)52 static inline moab::Range::PairNode* alloc_pair(moab::Range::PairNode* n, moab::Range::PairNode* p, moab::EntityHandle f, moab::EntityHandle s)
53 { return new moab::Range::PairNode(n,p,f,s); }
free_pair(moab::Range::PairNode * node)54 static inline void free_pair( moab::Range::PairNode* node )
55 { delete node; }
56 #endif
57
58 namespace moab {
59
60 /*!
61 returns the number of values this list represents
62 */
size() const63 size_t Range::size() const
64 {
65 // go through each pair and add up the number of values
66 // we have.
67 size_t sz=0;
68 for(PairNode* iter = mHead.mNext; iter != &mHead; iter = iter->mNext)
69 {
70 sz += ((iter->second - iter->first) + 1);
71 }
72 return sz;
73 }
74
75 /*!
76 advance iterator
77 */
operator +=(EntityID sstep)78 Range::const_iterator& Range::const_iterator::operator+=( EntityID sstep )
79 {
80 // Check negative now to avoid infinite loop below.
81 if (sstep < 0)
82 {
83 return operator-=( -sstep );
84 }
85 EntityHandle step = sstep;
86
87 // Handle current PairNode. Either step is within the current
88 // node or need to remove the remainder of the current node
89 // from step.
90 EntityHandle this_node_rem = mNode->second - mValue;
91 if (this_node_rem >= step)
92 {
93 mValue += step;
94 return *this;
95 }
96 step -= this_node_rem + 1;
97
98 // For each node we are stepping past, decrement step
99 // by the size of the node.
100 PairNode* node = mNode->mNext;
101 EntityHandle node_size = node->second - node->first + 1;
102 while (step >= node_size)
103 {
104 step -= node_size;
105 node = node->mNext;
106 node_size = node->second - node->first + 1;
107 }
108
109 // Advance into the resulting node by whatever is
110 // left in step.
111 mNode = node;
112 mValue = mNode->first + step;
113 return *this;
114 }
115
116
117
118 /*!
119 regress iterator
120 */
operator -=(EntityID sstep)121 Range::const_iterator& Range::const_iterator::operator-=( EntityID sstep )
122 {
123 // Check negative now to avoid infinite loop below.
124 if (sstep < 0)
125 {
126 return operator+=( -sstep );
127 }
128 EntityHandle step = sstep;
129
130 // Handle current PairNode. Either step is within the current
131 // node or need to remove the remainder of the current node
132 // from step.
133 EntityHandle this_node_rem = mValue - mNode->first;
134 if (this_node_rem >= step)
135 {
136 mValue -= step;
137 return *this;
138 }
139 step -= this_node_rem + 1;
140
141 // For each node we are stepping past, decrement step
142 // by the size of the node.
143 PairNode* node = mNode->mPrev;
144 EntityHandle node_size = node->second - node->first + 1;
145 while (step >= node_size)
146 {
147 step -= node_size;
148 node = node->mPrev;
149 node_size = node->second - node->first + 1;
150 }
151
152 // Advance into the resulting node by whatever is
153 // left in step.
154 mNode = node;
155 mValue = mNode->second - step;
156 return *this;
157 }
158
159
160
161
162 //! another constructor that takes an initial range
Range(EntityHandle val1,EntityHandle val2)163 Range::Range( EntityHandle val1, EntityHandle val2 )
164 {
165 mHead.mNext = mHead.mPrev = alloc_pair(&mHead, &mHead, val1, val2);
166 mHead.first = mHead.second = 0;
167 }
168
169 //! copy constructor
Range(const Range & copy)170 Range::Range(const Range& copy)
171 {
172 // set the head node to point to itself
173 mHead.mNext = mHead.mPrev = &mHead;
174 mHead.first = mHead.second = 0;
175
176 const PairNode* copy_node = copy.mHead.mNext;
177 PairNode* new_node = &mHead;
178 for(; copy_node != &(copy.mHead); copy_node = copy_node->mNext)
179 {
180 PairNode* tmp_node = alloc_pair(new_node->mNext, new_node, copy_node->first,
181 copy_node->second);
182 new_node->mNext->mPrev = tmp_node;
183 new_node->mNext = tmp_node;
184 new_node = tmp_node;
185 }
186 }
187
188 //! clears the contents of the list
clear()189 void Range::clear()
190 {
191 PairNode* tmp_node = mHead.mNext;
192 while(tmp_node != &mHead)
193 {
194 PairNode* to_delete = tmp_node;
195 tmp_node = tmp_node->mNext;
196 free_pair( to_delete );
197 }
198 mHead.mNext = &mHead;
199 mHead.mPrev = &mHead;
200 }
201
operator =(const Range & copy)202 Range& Range::operator=(const Range& copy)
203 {
204 clear();
205 const PairNode* copy_node = copy.mHead.mNext;
206 PairNode* new_node = &mHead;
207 for(; copy_node != &(copy.mHead); copy_node = copy_node->mNext)
208 {
209 PairNode* tmp_node = alloc_pair(new_node->mNext, new_node, copy_node->first,
210 copy_node->second);
211 new_node->mNext->mPrev = tmp_node;
212 new_node->mNext = tmp_node;
213 new_node = tmp_node;
214 }
215 return *this;
216 }
217
218
219 /*!
220 inserts a single value into this range
221 */
222
insert(Range::iterator hint,EntityHandle val)223 Range::iterator Range::insert( Range::iterator hint, EntityHandle val )
224 {
225 // don't allow zero-valued handles in Range
226 if(val == 0)
227 return end();
228
229 // if this is empty, just add it and return an iterator to it
230 if(&mHead == mHead.mNext)
231 {
232 mHead.mNext = mHead.mPrev = alloc_pair(&mHead, &mHead, val, val);
233 return iterator(mHead.mNext, val);
234 }
235
236 // find the location in the list where we can safely insert
237 // new items and keep it ordered
238 PairNode* hter = hint.mNode;
239 PairNode* jter = hter->first <= val ? hter : mHead.mNext;
240 for( ; (jter != &mHead) && (jter->second < val); jter=jter->mNext);
241 PairNode* iter = jter;
242 jter = jter->mPrev;
243
244 // if this val is already in the list
245 if( (iter->first <= val && iter->second >= val) && (iter != &mHead) )
246 {
247 // return an iterator pointing to this location
248 return iterator( iter, val );
249 }
250
251 // one of a few things can happen at this point
252 // 1. this range needs to be backwardly extended
253 // 2. the previous range needs to be forwardly extended
254 // 3. a new range needs to be added
255
256
257 // extend this range back a bit
258 else if( (iter->first == (val+1)) && (iter != &mHead) )
259 {
260 iter->first = val;
261 // see if we need to merge two ranges
262 if( (iter != mHead.mNext) && (jter->second == (val-1)))
263 {
264 jter->second = iter->second;
265 iter->mPrev->mNext = iter->mNext;
266 iter->mNext->mPrev = iter->mPrev;
267 free_pair( iter );
268 return iterator( jter, val );
269 }
270 else
271 {
272 return iterator( iter, val );
273 }
274
275 }
276 // extend the previous range forward a bit
277 else if( (jter->second == (val-1)) && (iter != mHead.mNext) )
278 {
279 jter->second = val;
280 return iterator(jter, val);
281 }
282 // make a new range
283 else
284 {
285 PairNode* new_node = alloc_pair(iter, iter->mPrev, val, val);
286 iter->mPrev = new_node->mPrev->mNext = new_node;
287 return iterator(new_node, val);
288 }
289
290 }
291
insert(Range::iterator prev,EntityHandle val1,EntityHandle val2)292 Range::iterator Range::insert( Range::iterator prev,
293 EntityHandle val1,
294 EntityHandle val2 )
295 {
296 if(val1 == 0 || val1 > val2)
297 return end();
298
299 // Empty
300 if (mHead.mNext == &mHead)
301 {
302 assert( prev == end() );
303 PairNode* new_node = alloc_pair( &mHead, &mHead, val1, val2 );
304 mHead.mNext = mHead.mPrev = new_node;
305 return iterator( mHead.mNext, val1 );
306 }
307
308 PairNode* iter = prev.mNode;
309 // If iterator is at end, set it to last.
310 // Thus if the hint was to append, we start searching
311 // at the end of the list.
312 if (iter == &mHead)
313 iter = mHead.mPrev;
314 // if hint (prev) is past insert position, reset it to the beginning.
315 if (iter != &mHead && iter->first > val2+1)
316 iter = mHead.mNext;
317
318 // If hint is bogus then search backwards
319 while (iter != mHead.mNext && iter->mPrev->second >= val1-1)
320 iter = iter->mPrev;
321
322 // Input range is before beginning?
323 if (iter->mPrev == &mHead && val2 < iter->first - 1)
324 {
325 PairNode* new_node = alloc_pair( iter, &mHead, val1, val2 );
326 mHead.mNext = iter->mPrev = new_node;
327 return iterator( mHead.mNext, val1 );
328 }
329
330 // Find first intersecting list entry, or the next entry
331 // if none intersects.
332 while (iter != &mHead && iter->second+1 < val1)
333 iter = iter->mNext;
334
335 // Need to insert new pair (don't intersect any existing pair)?
336 if (iter == &mHead || iter->first-1 > val2)
337 {
338 PairNode* new_node = alloc_pair( iter, iter->mPrev, val1, val2 );
339 iter->mPrev = iter->mPrev->mNext = new_node;
340 return iterator( iter->mPrev, val1 );
341 }
342
343 // Make the first intersecting pair the union of itself with [val1,val2]
344 if (iter->first > val1)
345 iter->first = val1;
346 if (iter->second >= val2)
347 return iterator( iter, val1 );
348 iter->second = val2;
349
350 // Merge any remaining pairs that intersect [val1,val2]
351 while (iter->mNext != &mHead && iter->mNext->first <= val2 + 1)
352 {
353 PairNode* dead = iter->mNext;
354 iter->mNext = dead->mNext;
355 dead->mNext->mPrev = iter;
356
357 if (dead->second > val2)
358 iter->second = dead->second;
359 free_pair( dead );
360 }
361
362 return iterator( iter, val1 );
363 }
364
365
366 /*!
367 erases an item from this list and returns an iterator to the next item
368 */
369
erase(iterator iter)370 Range::iterator Range::erase(iterator iter)
371 {
372 // one of a few things could happen
373 // 1. shrink a range
374 // 2. split a range
375 // 3. remove a range
376
377 if(iter == end())
378 return end();
379
380 // the iterator most likely to be returned
381 iterator new_iter = iter;
382 ++new_iter;
383
384 PairNode* kter = iter.mNode;
385
386 // just remove the range
387 if(kter->first == kter->second)
388 {
389 kter->mNext->mPrev = kter->mPrev;
390 kter->mPrev->mNext = kter->mNext;
391 free_pair( kter );
392 return new_iter;
393 }
394 // shrink it
395 else if(kter->first == iter.mValue)
396 {
397 kter->first++;
398 return new_iter;
399 }
400 // shrink it the other way
401 else if(kter->second == iter.mValue)
402 {
403 kter->second--;
404 return new_iter;
405 }
406 // split the range
407 else
408 {
409 PairNode* new_node = alloc_pair(iter.mNode->mNext, iter.mNode, iter.mValue+1, kter->second);
410 new_node->mPrev->mNext = new_node->mNext->mPrev = new_node;
411 iter.mNode->second = iter.mValue - 1;
412 new_iter = const_iterator(new_node, new_node->first);
413 return new_iter;
414 }
415
416 }
417
418
419 //! remove a range of items from the list
erase(iterator iter1,iterator iter2)420 Range::iterator Range::erase( iterator iter1, iterator iter2)
421 {
422 iterator result;
423
424 if (iter1.mNode == iter2.mNode) {
425 if (iter2.mValue <= iter1.mValue) {
426 // empty range OK, otherwise invalid input
427 return iter2;
428 }
429
430 // If both iterators reference the same pair node, then
431 // we're either removing values from the front of the
432 // node or splitting the node. We can never be removing
433 // the last value in the node in this case because iter2
434 // points *after* the last entry to be removed.
435
436 PairNode* node = iter1.mNode;
437 if (iter1.mValue == node->first) {
438 node->first = iter2.mValue;
439 result = iter2;
440 }
441 else {
442 PairNode* new_node = alloc_pair( node->mNext, node, iter2.mValue, node->second );
443 new_node->mNext->mPrev = new_node;
444 new_node->mPrev->mNext = new_node;
445 node->second = iter1.mValue - 1;
446 result = iterator( new_node, new_node->first );
447 }
448 }
449 else {
450 if (iter1.mNode == &mHead)
451 return iter1;
452 PairNode* dn = iter1.mNode;
453 if (iter1.mValue > dn->first) {
454 dn->second = iter1.mValue-1;
455 dn = dn->mNext;
456 }
457 if (iter2.mNode != &mHead)
458 iter2.mNode->first = iter2.mValue;
459 while (dn != iter2.mNode) {
460 PairNode* dead = dn;
461 dn = dn->mNext;
462
463 dead->mPrev->mNext = dead->mNext;
464 dead->mNext->mPrev = dead->mPrev;
465 dead->mPrev = dead->mNext = 0;
466 delete dead;
467 }
468
469 result = iter2;
470 }
471
472 return result;
473 }
474
delete_pair_node(PairNode * node)475 void Range::delete_pair_node( PairNode* node )
476 {
477 if (node != &mHead) { // pop_front() and pop_back() rely on this check
478 node->mPrev->mNext = node->mNext;
479 node->mNext->mPrev = node->mPrev;
480 free_pair( node );
481 }
482 }
483
484 //! remove first entity from range
pop_front()485 EntityHandle Range::pop_front()
486 {
487 EntityHandle retval = front();
488 if (mHead.mNext->first == mHead.mNext->second) // need to remove pair from range
489 delete_pair_node( mHead.mNext );
490 else
491 ++(mHead.mNext->first); // otherwise just adjust start value of pair
492
493 return retval;
494 }
495
496 //! remove last entity from range
pop_back()497 EntityHandle Range::pop_back()
498 {
499 EntityHandle retval = back();
500 if (mHead.mPrev->first == mHead.mPrev->second) // need to remove pair from range
501 delete_pair_node( mHead.mPrev );
502 else
503 --(mHead.mPrev->second); // otherwise just adjust end value of pair
504
505 return retval;
506 }
507
508 /*!
509 finds a value in the list.
510 this method is preferred over other algorithms because
511 it can be found faster this way.
512 */
find(EntityHandle val) const513 Range::const_iterator Range::find(EntityHandle val) const
514 {
515 // iterator through the list
516 PairNode* iter = mHead.mNext;
517 for( ; iter != &mHead && (val > iter->second); iter=iter->mNext );
518 return ((iter->second >= val) && (iter->first <= val)) ? const_iterator(iter,val) : end();
519 }
520
521 /*!
522 merges another Range with this one
523 */
524
insert(Range::const_iterator begini,Range::const_iterator endi)525 void Range::insert( Range::const_iterator begini,
526 Range::const_iterator endi )
527 {
528 if (begini == endi)
529 return;
530
531 PairNode* node = begini.mNode;
532 if (endi.mNode == node)
533 {
534 insert( *begini, (*endi)-1 );
535 return;
536 }
537
538 Range::iterator hint = insert( *begini, node->second );
539 node = node->mNext;
540 while (node != endi.mNode)
541 {
542 hint = insert( hint, node->first, node->second );
543 node = node->mNext;
544 }
545
546 if (*endi > node->first)
547 {
548 if (*endi <= node->second)
549 insert( hint, node->first, *(endi) - 1 );
550 else
551 insert( hint, node->first, node->second );
552 }
553 }
554
555
556
557
558 #include <algorithm>
559
560
561 // checks the range to make sure everything is A-Ok.
sanity_check() const562 void Range::sanity_check() const
563 {
564 if(empty())
565 return;
566
567 const PairNode* node = mHead.mNext;
568 std::vector<const PairNode*> seen_before;
569 bool stop_it = false;
570
571 for(; stop_it == false; node = node->mNext)
572 {
573 // have we seen this node before?
574 assert(std::find(seen_before.begin(), seen_before.end(), node) == seen_before.end());
575 seen_before.push_back(node);
576
577 // is the connection correct?
578 assert(node->mNext->mPrev == node);
579
580 // are the values right?
581 assert(node->first <= node->second);
582 if(node != &mHead && node->mPrev != &mHead)
583 assert(node->mPrev->second < node->first);
584
585 if(node == &mHead)
586 stop_it = true;
587
588 }
589
590 }
591
str_rep(const char * indent_prefix) const592 const std::string Range::str_rep(const char* indent_prefix) const {
593 std::stringstream str_stream;
594 std::string indent_prefix_str;
595 if (NULL != indent_prefix) {
596 indent_prefix_str += indent_prefix;
597 }
598
599 if (empty()) {
600 str_stream << indent_prefix_str << "\tempty" << std::endl;
601 return str_stream.str().c_str();
602 }
603
604 for (const_pair_iterator i = const_pair_begin(); i != const_pair_end(); ++i) {
605 EntityType t1 = TYPE_FROM_HANDLE( i->first );
606 EntityType t2 = TYPE_FROM_HANDLE( i->second );
607
608 str_stream << indent_prefix_str << "\t" << CN::EntityTypeName( t1 ) << " "
609 << ID_FROM_HANDLE( i->first );
610 if(i->first != i->second) {
611 str_stream << " - ";
612 if (t1 != t2)
613 str_stream << CN::EntityTypeName( t2 ) << " ";
614 str_stream << ID_FROM_HANDLE( i->second );
615 }
616 str_stream << std::endl;
617 }
618
619 return str_stream.str();
620 }
621
print(std::ostream & stream,const char * indent_prefix) const622 void Range::print(std::ostream& stream, const char *indent_prefix) const
623 {
624 stream << str_rep(indent_prefix);
625 }
626
627 // for debugging
print(const char * indent_prefix) const628 void Range::print(const char *indent_prefix) const
629 {
630 print(std::cout, indent_prefix);
631 }
632
633
634 // intersect two ranges, placing the results in the return range
635 #define MAX(a,b) (a < b ? b : a)
636 #define MIN(a,b) (a > b ? b : a)
intersect(const Range & range1,const Range & range2)637 Range intersect(const Range &range1, const Range &range2)
638 {
639 Range::const_pair_iterator r_it[2] = { range1.const_pair_begin(),
640 range2.const_pair_begin() };
641 EntityHandle low_it, high_it;
642
643 Range lhs;
644 Range::iterator hint = lhs.begin();
645
646 // terminate the while loop when at least one "start" iterator is at the
647 // end of the list
648 while (r_it[0] != range1.end() && r_it[1] != range2.end()) {
649
650 if (r_it[0]->second < r_it[1]->first)
651 // 1st subrange completely below 2nd subrange
652 ++r_it[0];
653 else if (r_it[1]->second < r_it[0]->first)
654 // 2nd subrange completely below 1st subrange
655 ++r_it[1];
656
657 else {
658 // else ranges overlap; first find greater start and lesser end
659 low_it = MAX(r_it[0]->first, r_it[1]->first);
660 high_it = MIN(r_it[0]->second, r_it[1]->second);
661
662 // insert into result
663 hint = lhs.insert(hint, low_it, high_it);
664
665 // now find bounds of this insertion and increment corresponding iterator
666 if (high_it == r_it[0]->second) ++r_it[0];
667 if (high_it == r_it[1]->second) ++r_it[1];
668 }
669 }
670
671 return lhs;
672 }
673
subtract(const Range & range1,const Range & range2)674 Range subtract(const Range &range1, const Range &range2)
675 {
676 const bool braindead = false;
677
678 if (braindead) {
679 // brain-dead implementation right now
680 Range res( range1 );
681 for (Range::const_iterator rit = range2.begin(); rit != range2.end(); ++rit)
682 res.erase(*rit);
683
684 return res;
685 }
686 else {
687 Range lhs( range1 );
688
689 Range::pair_iterator r_it0 = lhs.pair_begin();
690 Range::const_pair_iterator r_it1 = range2.const_pair_begin();
691
692 // terminate the while loop when at least one "start" iterator is at the
693 // end of the list
694 while (r_it0 != lhs.end() && r_it1 != range2.end()) {
695 // case a: pair wholly within subtracted pair
696 if (r_it0->first >= r_it1->first && r_it0->second <= r_it1->second) {
697 Range::PairNode *rtmp = r_it0.node();
698 ++r_it0;
699 lhs.delete_pair_node(rtmp);
700 }
701 // case b: pair overlaps upper part of subtracted pair
702 else if (r_it0->first <= r_it1->second &&
703 r_it0->first >= r_it1->first) {
704 r_it0->first = r_it1->second + 1;
705 ++r_it1;
706 }
707 // case c: pair overlaps lower part of subtracted pair
708 else if (r_it0->second >= r_it1->first &&
709 r_it0->second <= r_it1->second) {
710 r_it0->second = r_it1->first - 1;
711 ++r_it0;
712 }
713 // case d: pair completely surrounds subtracted pair
714 else if (r_it0->first < r_it1->first &&
715 r_it0->second > r_it1->second) {
716 Range::PairNode* new_node = alloc_pair(r_it0.node(), r_it0.node()->mPrev,
717 r_it0->first, r_it1->first - 1);
718 new_node->mPrev->mNext = new_node->mNext->mPrev = new_node;
719 r_it0.node()->first = r_it1->second+1;
720 ++r_it1;
721 }
722 else {
723 while (r_it0->second < r_it1->first && r_it0 != lhs.end()) ++r_it0;
724 if (r_it0 == lhs.end()) break;
725 while (r_it1->second < r_it0->first && r_it1 != range2.end()) ++r_it1;
726 }
727 }
728
729 return lhs;
730 }
731 }
732
operator -=(const Range & range2)733 Range &Range::operator-=(const Range &range2)
734 {
735 const bool braindead = false;
736
737 if (braindead) {
738 // brain-dead implementation right now
739 Range res( *this );
740 for (Range::const_iterator rit = range2.begin(); rit != range2.end(); ++rit)
741 res.erase(*rit);
742
743 return *this;
744 }
745 else {
746 Range::pair_iterator r_it0 = this->pair_begin();
747 Range::const_pair_iterator r_it1 = range2.const_pair_begin();
748
749 // terminate the while loop when at least one "start" iterator is at the
750 // end of the list
751 while (r_it0 != this->end() && r_it1 != range2.end()) {
752 // case a: pair wholly within subtracted pair
753 if (r_it0->first >= r_it1->first && r_it0->second <= r_it1->second) {
754 Range::PairNode *rtmp = r_it0.node();
755 ++r_it0;
756 this->delete_pair_node(rtmp);
757 }
758 // case b: pair overlaps upper part of subtracted pair
759 else if (r_it0->first <= r_it1->second &&
760 r_it0->first >= r_it1->first) {
761 r_it0->first = r_it1->second + 1;
762 ++r_it1;
763 }
764 // case c: pair overlaps lower part of subtracted pair
765 else if (r_it0->second >= r_it1->first &&
766 r_it0->second <= r_it1->second) {
767 r_it0->second = r_it1->first - 1;
768 ++r_it0;
769 }
770 // case d: pair completely surrounds subtracted pair
771 else if (r_it0->first < r_it1->first &&
772 r_it0->second > r_it1->second) {
773 Range::PairNode* new_node = alloc_pair(r_it0.node(), r_it0.node()->mPrev,
774 r_it0->first, r_it1->first - 1);
775 new_node->mPrev->mNext = new_node->mNext->mPrev = new_node;
776 r_it0.node()->first = r_it1->second+1;
777 ++r_it1;
778 }
779 else {
780 while (r_it0->second < r_it1->first && r_it0 != this->end()) ++r_it0;
781 if (r_it0 == this->end()) break;
782 while (r_it1->second < r_it0->first && r_it1 != range2.end()) ++r_it1;
783 }
784 }
785 return *this;
786 }
787 }
788
789
790 EntityID
operator -(const Range::const_iterator & it2,const Range::const_iterator & it1)791 operator-( const Range::const_iterator& it2, const Range::const_iterator& it1 )
792 {
793 assert( !it2.mValue || *it2 >= *it1 );
794 if (it2.mNode == it1.mNode) {
795 return *it2 - *it1;
796 }
797
798 EntityID result = it1.mNode->second - it1.mValue + 1;
799 for (Range::PairNode* n = it1.mNode->mNext; n != it2.mNode; n = n->mNext)
800 result += n->second - n->first + 1;
801 if (it2.mValue) // (it2.mNode != &mHead)
802 result += it2.mValue - it2.mNode->first;
803 return result;
804 }
805
806
lower_bound(Range::const_iterator first,Range::const_iterator last,EntityHandle val)807 Range::const_iterator Range::lower_bound(Range::const_iterator first,
808 Range::const_iterator last,
809 EntityHandle val)
810 {
811 // Find the first pair whose end is >= val
812 PairNode* iter;
813 for (iter = first.mNode; iter != last.mNode; iter = iter->mNext)
814 {
815 if (iter->second >= val)
816 {
817 // This is the correct pair. Either 'val' is in the range, or
818 // the range starts before 'val' and iter->first IS the lower_bound.
819 if (iter->first > val)
820 return const_iterator(iter, iter->first);
821 return const_iterator(iter, val);
822 }
823 }
824
825 if (iter->first >= val)
826 return const_iterator( iter, iter->first );
827 else if(*last > val)
828 return const_iterator( iter, val );
829 else
830 return last;
831 }
832
upper_bound(Range::const_iterator first,Range::const_iterator last,EntityHandle val)833 Range::const_iterator Range::upper_bound(Range::const_iterator first,
834 Range::const_iterator last,
835 EntityHandle val)
836 {
837 Range::const_iterator result = lower_bound( first, last, val );
838 if (result != last && *result == val)
839 ++result;
840 return result;
841 }
842
lower_bound(EntityType type) const843 Range::const_iterator Range::lower_bound( EntityType type ) const
844 {
845 int err;
846 EntityHandle handle = CREATE_HANDLE( type, 0, err );
847 return err ? end() : lower_bound( begin(), end(), handle );
848 }
lower_bound(EntityType type,const_iterator first) const849 Range::const_iterator Range::lower_bound( EntityType type,
850 const_iterator first ) const
851 {
852 int err;
853 EntityHandle handle = CREATE_HANDLE( type, 0, err );
854 return err ? end() : lower_bound( first, end(), handle );
855 }
856
upper_bound(EntityType type) const857 Range::const_iterator Range::upper_bound( EntityType type ) const
858 {
859 // if (type+1) overflows, err will be true and we return end().
860 int err;
861 EntityHandle handle = CREATE_HANDLE( type + 1, 0, err );
862 return err ? end() : lower_bound( begin(), end(), handle );
863 }
upper_bound(EntityType type,const_iterator first) const864 Range::const_iterator Range::upper_bound( EntityType type,
865 const_iterator first ) const
866 {
867 // if (type+1) overflows, err will be true and we return end().
868 int err;
869 EntityHandle handle = CREATE_HANDLE( type + 1, 0, err );
870 return err ? end() : lower_bound( first, end(), handle );
871 }
872
873 std::pair<Range::const_iterator, Range::const_iterator>
equal_range(EntityType type) const874 Range::equal_range( EntityType type ) const
875 {
876 std::pair<Range::const_iterator, Range::const_iterator> result;
877 int err;
878 EntityHandle handle = CREATE_HANDLE( type, 0, err );
879 result.first = err ? end() : lower_bound( begin(), end(), handle );
880 // if (type+1) overflows, err will be true and we return end().
881 handle = CREATE_HANDLE( type+1, 0, err );
882 result.second = err ? end() : lower_bound( result.first, end(), handle );
883 return result;
884 }
885
all_of_type(EntityType type) const886 bool Range::all_of_type( EntityType type ) const
887 {
888 return empty()
889 || (TYPE_FROM_HANDLE(front()) == type
890 && TYPE_FROM_HANDLE(back()) == type);
891 }
892
all_of_dimension(int dimension) const893 bool Range::all_of_dimension( int dimension ) const
894 {
895 return empty()
896 || (CN::Dimension(TYPE_FROM_HANDLE(front())) == dimension
897 && CN::Dimension(TYPE_FROM_HANDLE(back())) == dimension);
898 }
899
num_of_type(EntityType type) const900 unsigned Range::num_of_type( EntityType type ) const
901 {
902 const_pair_iterator iter = const_pair_begin();
903 while(iter != const_pair_end() && TYPE_FROM_HANDLE((*iter).second) < type)
904 ++iter;
905
906 unsigned count = 0;
907 for ( ; iter != const_pair_end(); ++iter)
908 {
909 EntityType start_type = TYPE_FROM_HANDLE((*iter).first);
910 EntityType end_type = TYPE_FROM_HANDLE((*iter).second);
911 if (start_type > type)
912 break;
913
914 EntityID sid = start_type < type ? 1 : ID_FROM_HANDLE((*iter).first);
915 EntityID eid = end_type > type ? MB_END_ID : ID_FROM_HANDLE((*iter).second);
916 count += eid - sid + 1;
917 }
918
919 return count;
920 }
921
num_of_dimension(int dim) const922 unsigned Range::num_of_dimension( int dim ) const
923 {
924 const_pair_iterator iter = const_pair_begin();
925 while(iter != const_pair_end() && CN::Dimension(TYPE_FROM_HANDLE((*iter).second)) < dim)
926 ++iter;
927
928 int junk;
929 unsigned count = 0;
930 for ( ; iter != const_pair_end(); ++iter)
931 {
932 int start_dim = CN::Dimension(TYPE_FROM_HANDLE((*iter).first));
933 int end_dim = CN::Dimension(TYPE_FROM_HANDLE((*iter).second));
934 if (start_dim > dim)
935 break;
936
937 EntityHandle sh = start_dim < dim ?
938 CREATE_HANDLE( CN::TypeDimensionMap[dim].first, 1, junk ) :
939 (*iter).first;
940 EntityHandle eh = end_dim > dim ?
941 CREATE_HANDLE( CN::TypeDimensionMap[dim].second, MB_END_ID, junk ) :
942 (*iter).second;
943 count += eh - sh + 1;
944 }
945
946 return count;
947 }
948
949
950
951
952 //! swap the contents of this range with another one
953 //! THIS FUNCTION MUST NOT BE INLINED, THAT WILL ELIMINATE RANGE_EMPTY AND THIS_EMPTY
954 //! BY SUBSTITUTION AND THE FUNCTION WON'T WORK RIGHT!
swap(Range & range)955 void Range::swap( Range &range )
956 {
957 // update next/prev nodes of head of both ranges
958 bool range_empty = (range.mHead.mNext == &(range.mHead));
959 bool this_empty = (mHead.mNext == &mHead);
960
961 range.mHead.mNext->mPrev = (range_empty ? &(range.mHead) : &mHead);
962 range.mHead.mPrev->mNext = (range_empty ? &(range.mHead) : &mHead);
963 mHead.mNext->mPrev = (this_empty ? &mHead : &(range.mHead));
964 mHead.mPrev->mNext = (this_empty ? &mHead : &(range.mHead));
965
966 // switch data in head nodes of both ranges
967 PairNode *range_next = range.mHead.mNext, *range_prev = range.mHead.mPrev;
968 range.mHead.mNext = (this_empty ? &(range.mHead) : mHead.mNext);
969 range.mHead.mPrev = (this_empty ? &(range.mHead) : mHead.mPrev);
970 mHead.mNext = (range_empty ? &mHead : range_next);
971 mHead.mPrev = (range_empty ? &mHead : range_prev);
972
973 }
974
975 //! return a subset of this range, by type
subset_by_type(EntityType t) const976 Range Range::subset_by_type(EntityType t) const
977 {
978 Range result;
979 std::pair<const_iterator, const_iterator> iters = equal_range(t);
980 result.insert( iters.first, iters.second );
981 return result;
982 }
983
984 //! return a subset of this range, by type
subset_by_dimension(int d) const985 Range Range::subset_by_dimension( int d ) const
986 {
987 EntityHandle handle1 = CREATE_HANDLE( CN::TypeDimensionMap[d].first, 0 );
988 iterator st = lower_bound( begin(), end(), handle1 );
989
990 iterator en;
991 if (d < 4) { // dimension 4 is MBENTITYSET
992 EntityHandle handle2 = CREATE_HANDLE( CN::TypeDimensionMap[d+1].first, 0 );
993 en = lower_bound( st, end(), handle2 );
994 }
995 else {
996 en = end();
997 }
998
999 Range result;
1000 result.insert( st, en );
1001 return result;
1002 }
1003
operator ==(const Range & r1,const Range & r2)1004 bool operator==( const Range& r1, const Range& r2 )
1005 {
1006 Range::const_pair_iterator i1, i2;
1007 i1 = r1.const_pair_begin();
1008 i2 = r2.const_pair_begin();
1009 for ( ; i1 != r1.const_pair_end(); ++i1, ++i2)
1010 if (i2 == r2.const_pair_end() ||
1011 i1->first != i2->first ||
1012 i1->second != i2->second)
1013 return false;
1014 return i2 == r2.const_pair_end();
1015 }
1016
get_memory_use() const1017 unsigned long Range::get_memory_use() const
1018 {
1019 unsigned long result = 0;
1020 for (const PairNode* n = mHead.mNext; n != &mHead; n = n->mNext)
1021 result += sizeof(PairNode);
1022 return result;
1023 }
1024
contains(const Range & othr) const1025 bool Range::contains( const Range& othr ) const
1026 {
1027 if (othr.empty())
1028 return true;
1029 if (empty())
1030 return false;
1031
1032 // neither range is empty, so both have valid pair nodes
1033 // other than dummy mHead
1034 const PairNode* this_node = mHead.mNext;
1035 const PairNode* othr_node = othr.mHead.mNext;
1036 for(;;) {
1037 // Loop while the node in this list is entirely before
1038 // the node in the other list.
1039 while (this_node->second < othr_node->first) {
1040 this_node = this_node->mNext;
1041 if (this_node == &mHead)
1042 return false;
1043 }
1044 // If other node is not entirely contained in this node
1045 // then other list is not contained in this list
1046 if (this_node->first > othr_node->first)
1047 break;
1048 // Loop while other node is entirely contained in this node.
1049 while (othr_node->second <= this_node->second) {
1050 othr_node = othr_node->mNext;
1051 if (othr_node == &othr.mHead)
1052 return true;
1053 }
1054 // If other node overlapped end of this node
1055 if (othr_node->first <= this_node->second)
1056 break;
1057 }
1058
1059 // should be unreachable
1060 return false;
1061 }
1062
1063 } // namespace moab
1064