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 /**\file RangeSeqIntersectIter.cpp
17  *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
18  *\date 2006-08-11
19  */
20 
21 #include "RangeSeqIntersectIter.hpp"
22 #include "SequenceManager.hpp"
23 #include "EntitySequence.hpp"
24 #include <assert.h>
25 
26 namespace moab {
27 
init(Range::const_iterator start,Range::const_iterator end)28 ErrorCode RangeSeqIntersectIter::init( Range::const_iterator start,
29                                            Range::const_iterator end )
30 {
31   mSequence = 0;
32   rangeIter = start;
33 
34     // special case : nothing to iterate over
35   if (start == end) {
36     mStartHandle = mEndHandle = mLastHandle = 0;
37     return MB_FAILURE;
38   }
39 
40     // normal case
41   mStartHandle = *start;
42   --end;
43   mLastHandle = *end;
44   mEndHandle = (*rangeIter).second;
45   if (mEndHandle > mLastHandle)
46     mEndHandle = mLastHandle;
47 
48 #if MB_RANGE_SEQ_INTERSECT_ITER_STATS
49   ErrorCode result = update_entity_sequence();
50   update_stats(mEndHandle - mStartHandle + 1);
51   return result;
52 #else
53   return update_entity_sequence();
54 #endif
55 }
56 
57 
step()58 ErrorCode RangeSeqIntersectIter::step()
59 {
60     // If at end, return MB_FAILURE
61   if (is_at_end())
62     return MB_FAILURE;
63     // If the last block was at the end of the rangeIter pair,
64     // then advance the iterator and set the next block
65   else if (mEndHandle == (*rangeIter).second) {
66     ++rangeIter;
67     mStartHandle = (*rangeIter).first;
68   }
69     // Otherwise start with next entity in the pair
70   else {
71     mStartHandle = mEndHandle + 1;
72   }
73     // Always take the remaining entities in the rangeIter pair.
74     // will trim up the end of the range in update_entity_sequence().
75   mEndHandle = (*rangeIter).second;
76   if (mEndHandle > mLastHandle)
77     mEndHandle = mLastHandle;
78 
79     // Now trim up the range (decrease mEndHandle) as necessary
80     // for the corresponding EntitySquence
81 #if MB_RANGE_SEQ_INTERSECT_ITER_STATS
82   ErrorCode result = update_entity_sequence();
83   update_stats(mEndHandle - mStartHandle + 1);
84   return result;
85 #else
86   return update_entity_sequence();
87 #endif
88 }
89 
update_entity_sequence()90 ErrorCode RangeSeqIntersectIter::update_entity_sequence()
91 {
92     // mStartHandle to mEndHandle is a subset of the Range.
93     // Update sequence data as necessary and trim that subset
94     // (reduce mEndHandle) for the current EntitySequence.
95 
96     // Need to update the sequence pointer?
97   if (!mSequence || mStartHandle > mSequence->end_handle()) {
98 
99       // Check that the mStartHandle is valid
100     if (TYPE_FROM_HANDLE(mStartHandle) >= MBMAXTYPE)
101       return MB_TYPE_OUT_OF_RANGE;
102 
103     if (MB_SUCCESS != mSequenceManager->find( mStartHandle, mSequence ))
104       return find_invalid_range();
105   }
106 
107     // if mEndHandle is past end of sequence or block of used
108     // handles within sequence, shorten it.
109   if(mEndHandle > mSequence->end_handle())
110     mEndHandle = mSequence->end_handle();
111 
112   return MB_SUCCESS;
113 }
114 
find_invalid_range()115 ErrorCode RangeSeqIntersectIter::find_invalid_range()
116 {
117   assert(!mSequence);
118 
119     // no more entities in current range
120   if (mStartHandle == mEndHandle)
121     return MB_ENTITY_NOT_FOUND;
122 
123     // Find the next EntitySequence
124   EntityType type = TYPE_FROM_HANDLE(mStartHandle);
125   const TypeSequenceManager& map = mSequenceManager->entity_map( type );
126   TypeSequenceManager::const_iterator iter = map.upper_bound( mStartHandle );
127     // If no next sequence of the same type
128   if (iter == map.end()) {
129       // If end type not the same as start type, split on type
130     if (type != TYPE_FROM_HANDLE( mEndHandle )) {
131       int junk;
132       mEndHandle = CREATE_HANDLE( type, MB_END_ID, junk );
133     }
134   }
135     // otherwise invalid range ends at min(mEndHandle, sequence start handle - 1)
136   else if ((*iter)->start_handle() <= mEndHandle) {
137     mEndHandle = (*iter)->start_handle()-1;
138   }
139 
140   return MB_ENTITY_NOT_FOUND;
141 }
142 
143 #if MB_RANGE_SEQ_INTERSECT_ITER_STATS
144 double RangeSeqIntersectIter::doubleNumCalls = 0;
145 double RangeSeqIntersectIter::doubleEntCount = 0;
146 unsigned long RangeSeqIntersectIter::intNumCalls = 0;
147 unsigned long RangeSeqIntersectIter::intEntCount = 0;
148 
update_stats(unsigned long num_ents)149 void RangeSeqIntersectIter::update_stats( unsigned long num_ents )
150 {
151   if (std::numeric_limits<unsigned long>::max() == intNumCalls) {
152     doubleNumCalls += intNumCalls;
153     intNumCalls = 0;
154   }
155   ++intNumCalls;
156 
157   if (std::numeric_limits<unsigned long>::max() - intEntCount > num_ents) {
158     doubleNumCalls += intEntCount;
159     intEntCount = num_ents;
160   }
161   else {
162     intEntCount += num_ents;
163   }
164 }
165 #endif
166 
167 } // namespace moab
168 
169