1 #include "TypeSequenceManager.hpp"
2 #include "SequenceData.hpp"
3 #include "moab/Error.hpp"
4 #include <assert.h>
5 #include <limits>
6 
7 namespace moab {
8 
~TypeSequenceManager()9 TypeSequenceManager::~TypeSequenceManager()
10 {
11   // We assume that for there to be multiple sequences referencing
12   // the same SequenceData, there must be some portion of the
13   // SequenceData that is unused. Otherwise the sequences should
14   // have been merged. Given that assumption, it is the case that
15   // either a) a SequenceData is in availableList or b) the
16   // SequenceData is referenced by exactly one sequence.
17 
18   // Delete every entity sequence
19   for (iterator i = begin(); i != end(); ++i) {
20     EntitySequence* seq = *i;
21     // Check for case b) above
22     if (seq->using_entire_data()) {
23       // Delete sequence before data, because sequence
24       // has a pointer to data and may try to dereference
25       // that pointer during its destruction.
26       SequenceData* data = seq->data();
27       delete seq;
28       delete data;
29     }
30     else {
31       delete seq;
32     }
33   }
34   sequenceSet.clear();
35 
36   // Case a) above
37   for (data_iterator i = availableList.begin(); i != availableList.end(); ++i)
38     delete *i;
39   availableList.clear();
40 }
41 
merge_internal(iterator i,iterator j)42 ErrorCode TypeSequenceManager::merge_internal(iterator i, iterator j)
43 {
44   EntitySequence* dead = *j;
45   sequenceSet.erase(j);
46   ErrorCode rval = (*i)->merge(*dead);
47   if (MB_SUCCESS != rval) {
48     sequenceSet.insert(dead);
49     return rval;
50   }
51 
52   if (lastReferenced == dead)
53     lastReferenced = *i;
54   delete dead;
55 
56   // If merging results in no unused portions of the SequenceData,
57   // remove it from the available list.
58   if ((*i)->using_entire_data())
59     availableList.erase((*i)->data());
60 
61   return MB_SUCCESS;
62 }
63 
check_merge_next(iterator i)64 ErrorCode TypeSequenceManager::check_merge_next(iterator i)
65 {
66   iterator j = i; ++j;
67   if (j == end() || (*j)->data() != (*i)->data() ||
68      (*j)->start_handle() > (*i)->end_handle() + 1)
69     return MB_SUCCESS;
70 
71   assert((*i)->end_handle() + 1 == (*j)->start_handle());
72   return merge_internal(i, j);
73 }
74 
check_merge_prev(iterator i)75 ErrorCode TypeSequenceManager::check_merge_prev(iterator i)
76 {
77   if (i == begin())
78     return MB_SUCCESS;
79 
80   iterator j = i; --j;
81   if ((*j)->data() != (*i)->data() ||
82      (*j)->end_handle() + 1 < (*i)->start_handle())
83     return MB_SUCCESS;
84 
85   assert((*j)->end_handle() + 1 == (*i)->start_handle());
86   return merge_internal(i, j);
87 }
88 
insert_sequence(EntitySequence * seq_ptr)89 ErrorCode TypeSequenceManager::insert_sequence(EntitySequence* seq_ptr)
90 {
91   if (!seq_ptr->data())
92     return MB_FAILURE;
93 
94   if (seq_ptr->data()->start_handle() > seq_ptr->start_handle() ||
95       seq_ptr->data()->end_handle() < seq_ptr->end_handle() ||
96       seq_ptr->end_handle() < seq_ptr->start_handle())
97     return MB_FAILURE;
98 
99   iterator i = lower_bound(seq_ptr->start_handle());
100   if (i != end()) {
101     if ((*i)->start_handle() <= seq_ptr->end_handle())
102       return MB_ALREADY_ALLOCATED;
103     if (seq_ptr->data() != (*i)->data() &&
104         (*i)->data()->start_handle() <= seq_ptr->data()->end_handle())
105       return MB_ALREADY_ALLOCATED;
106   }
107 
108   if (i != begin()) {
109     iterator j = i; --j;
110     if (seq_ptr->data() != (*j)->data() &&
111         (*j)->data()->end_handle() >= seq_ptr->data()->start_handle())
112       return MB_ALREADY_ALLOCATED;
113   }
114 
115   i = sequenceSet.insert(i, seq_ptr);
116 
117   // Merge with previous sequence ?
118   if (seq_ptr->start_handle() > seq_ptr->data()->start_handle() && i != begin()) {
119     if (MB_SUCCESS != check_merge_prev(i)) {
120       sequenceSet.erase(i);
121       return MB_FAILURE;
122     }
123   }
124 
125   // Merge with next sequence ?
126   if ((*i)->end_handle() < (*i)->data()->end_handle()) {
127     if (MB_SUCCESS != check_merge_next(i)) {
128       sequenceSet.erase(i);
129       return MB_FAILURE;
130     }
131   }
132 
133   // We merged adjacent sequences sharing a SequenceData, so
134   // we can safely assume that unless this EntitySequence is
135   // using the entire SequenceData, there are unused portions.
136   if (!seq_ptr->using_entire_data())
137     availableList.insert(seq_ptr->data());
138 
139   // lastReferenced is only allowed to be NULL if there are
140   // no sequences (avoids unnecessary if's in fast path).
141   if (!lastReferenced)
142     lastReferenced = seq_ptr;
143 
144   // Each SequenceData has a pointer to the first EntitySequence
145   // referencing it. Update that pointer if the new sequence is
146   // the first one.
147   if ((*i)->start_handle() == (*i)->data()->start_handle() ||
148       lower_bound((*i)->data()->start_handle()) == i)
149     (*i)->data()->seqManData.firstSequence = i;
150 
151   assert(check_valid_data(seq_ptr));
152   return MB_SUCCESS;
153 }
154 
replace_subsequence(EntitySequence * seq_ptr,const int * tag_sizes,int num_tag_sizes)155 ErrorCode TypeSequenceManager::replace_subsequence(EntitySequence* seq_ptr,
156                                                    const int* tag_sizes,
157                                                    int num_tag_sizes)
158 {
159   // Find the sequence of interest
160   iterator i = lower_bound(seq_ptr->start_handle());
161   if (i == end() || (*i)->data() == seq_ptr->data())
162     return MB_FAILURE;
163   // New sequence must be a subset of an existing one
164   if (seq_ptr->start_handle() < (*i)->start_handle() ||
165       seq_ptr->end_handle() > (*i)->end_handle())
166     return MB_FAILURE;
167   // New sequence's data must be new also, and cannot intersect
168   // any existing sequence (just require that the data range
169   // matches the sequence range for now)
170   if (!seq_ptr->using_entire_data())
171     return MB_FAILURE;
172   // Copy tag data (move ownership of var-len data)
173   SequenceData* const dead_data = (*i)->data();
174   dead_data->move_tag_data(seq_ptr->data(), tag_sizes, num_tag_sizes);
175 
176   // Split sequences sharing old data into two groups:
177   // p->i : first sequence to i
178   // i->n : i to one past last sequence
179   iterator p, n = i;
180   p = (*i)->data()->seqManData.firstSequence;
181   for (++n; n != end() && (*n)->data() == (*i)->data(); ++n);
182 
183   // First subdivide EntitySequence as necessary
184   // Move i to be the first sequence past the insertion point
185   // such that the new order will be:
186   // [p,i-1] seq_ptr [i,n]
187   // where p == i if no previous sequence
188 
189   // Four possible cases:
190   // 0. All entities in sequence are in new sequence
191   // 1. Old entities in sequence before and after new sequence,
192   //    requiring sequence to be split.
193   // 2. Old entities after new sequence
194   // 3. Old entities before new sequence
195   const bool some_before = ((*i)->start_handle() < seq_ptr->start_handle());
196   const bool some_after  = ((*i)->  end_handle() > seq_ptr->  end_handle());
197   // Case 0
198   if (!(some_before || some_after)) {
199     // Remove dead sequence from internal lists
200     EntitySequence* seq = *i;
201     iterator dead = i; ++i;
202     if (p == dead)
203       p = i;
204     sequenceSet.erase(dead);
205 
206     // Delete old sequence
207     delete seq;
208     // Make sure lastReferenced isn't stale
209     if (lastReferenced == seq)
210       lastReferenced = seq_ptr;
211   }
212   // Case 1
213   else if (some_before && some_after) {
214     i = split_sequence(i, seq_ptr->start_handle());
215     (*i)->pop_front(seq_ptr->size());
216   }
217   // Case 2
218   else if (some_after) {
219     (*i)->pop_front(seq_ptr->size());
220   }
221   // Case 3
222   else { // some_before
223     (*i)->pop_back(seq_ptr->size());
224     ++i;
225   }
226 
227   // Now subdivide the underlying sequence data as necessary
228   availableList.erase(dead_data);
229   if (p != i) {
230     iterator last = i; --last;
231     SequenceData* new_data = (*p)->create_data_subset((*p)->start_handle(), (*last)->end_handle());
232     new_data->seqManData.firstSequence = p;
233 
234     for (; p != i; ++p)
235       (*p)->data(new_data);
236     // Copy tag data (move ownership of var-len data)
237     dead_data->move_tag_data(new_data, tag_sizes, num_tag_sizes);
238     if (!(*new_data->seqManData.firstSequence)->using_entire_data())
239       availableList.insert(new_data);
240   }
241   if (i != n) {
242     iterator last = n; --last;
243     SequenceData* new_data = (*i)->create_data_subset((*i)->start_handle(), (*last)->end_handle());
244     new_data->seqManData.firstSequence = i;
245     for (; i != n; ++i)
246       (*i)->data(new_data);
247     // Copy tag data (move ownership of var-len data)
248     dead_data->move_tag_data(new_data, tag_sizes, num_tag_sizes);
249     if (!(*new_data->seqManData.firstSequence)->using_entire_data())
250       availableList.insert(new_data);
251   }
252   delete dead_data;
253 
254   // Put new sequence in lists
255   return insert_sequence(seq_ptr);
256 }
257 
erase(iterator i)258 TypeSequenceManager::iterator TypeSequenceManager::erase(iterator i)
259 {
260   EntitySequence* seq = *i;
261   SequenceData* data = seq->data();
262   iterator j;
263 
264   // Check if we need to delete the referenced SequenceData also
265   bool delete_data;
266   if (seq->using_entire_data()) // Only sequence
267     delete_data = true;
268   else if (data->seqManData.firstSequence != i) { // Earlier sequence?
269     delete_data = false;
270     availableList.insert(data);
271   }
272   else { // Later sequence ?
273     j = i; ++j;
274     delete_data = (j == end() || (*j)->data() != data);
275     if (delete_data)
276       availableList.erase(data);
277     else {
278       availableList.insert(data);
279       data->seqManData.firstSequence = j;
280     }
281   }
282 
283   // Remove sequence, updating i to be next sequence
284   j = i++;
285   sequenceSet.erase(j);
286 
287   // Make sure lastReferenced isn't stale. It can only be NULL if
288   // no sequences.
289   if (lastReferenced == seq)
290     lastReferenced = sequenceSet.empty() ? 0 : *sequenceSet.begin();
291 
292   // Always delete sequence before the SequenceData it references.
293   assert(0 == find(seq->start_handle()));
294   delete seq;
295   if (delete_data)
296     delete data;
297   else {
298     assert(check_valid_data(*data->seqManData.firstSequence));
299     assert(lastReferenced != seq);
300   }
301   return i;
302 }
303 
remove_sequence(const EntitySequence * seq_ptr,bool & unreferenced_data)304 ErrorCode TypeSequenceManager::remove_sequence(const EntitySequence* seq_ptr,
305                                                bool& unreferenced_data)
306 {
307   // Remove sequence from set
308   iterator i = lower_bound(seq_ptr->start_handle());
309   if (i == end() || *i != seq_ptr)
310     return MB_ENTITY_NOT_FOUND;
311   sequenceSet.erase(i);
312 
313   // Check if this is the only sequence referencing its data
314   if (seq_ptr->using_entire_data())
315     unreferenced_data = true;
316   else {
317     i = lower_bound(seq_ptr->data()->start_handle());
318     unreferenced_data = i == end() || (*i)->data() != seq_ptr->data();
319     if (unreferenced_data)
320       availableList.erase(seq_ptr->data());
321     else
322       seq_ptr->data()->seqManData.firstSequence = i; // Might be 'i' already
323   }
324 
325   if (lastReferenced == seq_ptr)
326     lastReferenced = sequenceSet.empty() ? 0 : *sequenceSet.begin();
327 
328   return MB_SUCCESS;
329 }
330 
331 TypeSequenceManager::iterator
find_free_handle(EntityHandle min_start_handle,EntityHandle max_end_handle,bool & append_out,int values_per_ent)332 TypeSequenceManager::find_free_handle(EntityHandle min_start_handle,
333                                       EntityHandle max_end_handle,
334                                       bool& append_out,
335                                       int values_per_ent)
336 {
337   for (data_iterator i = availableList.begin(); i != availableList.end(); ++i) {
338     if ((*(*i)->seqManData.firstSequence)->values_per_entity() != values_per_ent)
339       continue;
340 
341     if ((*i)->start_handle() > max_end_handle || (*i)->end_handle() < min_start_handle)
342       continue;
343 
344     for (iterator j = (*i)->seqManData.firstSequence;
345          j != end() && (*j)->start_handle() <= (max_end_handle + 1) && (*j)->data() == *i;
346          ++j) {
347       if ((*j)->end_handle() + 1 < min_start_handle)
348         continue;
349       if ((*j)->start_handle() > (*i)->start_handle() &&
350           (*j)->start_handle() > min_start_handle) {
351         append_out = false;
352         return j;
353       }
354       if ((*j)->end_handle() < (*i)->end_handle() &&
355           (*j)->end_handle() < max_end_handle) {
356         append_out = true;
357         return j;
358       }
359     }
360   }
361 
362   return end();
363 }
364 
is_free_sequence(EntityHandle start,EntityID num_entities,SequenceData * & data_out,int values_per_ent)365 bool TypeSequenceManager::is_free_sequence(EntityHandle start,
366                                            EntityID num_entities,
367                                            SequenceData*& data_out,
368                                            int values_per_ent)
369 {
370   data_out = 0;
371   if (empty())
372     return true;
373 
374   const_iterator i = lower_bound(start);
375   if (i == end()) {
376     --i; // Safe because already tested empty()
377     // If we don't overlap the last data object...
378     if ((*i)->data()->end_handle() < start)
379       return true;
380     data_out = (*i)->data();
381     if ((*i)->values_per_entity() != values_per_ent)
382       return false;
383     // If we overlap a data object, we must be entirely inside of it
384     return start + num_entities - 1 <= (*i)->data()->end_handle();
385   }
386 
387 #ifndef NDEBUG
388   if (i != begin()) {
389     const_iterator j = i;
390     --j;
391     assert((*j)->end_handle() < start);
392   }
393 #endif
394 
395   // Check if we fit in the block of free handles
396   if (start + num_entities > (*i)->start_handle()) // start + num + 1 >= i->start
397     return false;
398 
399   // Check if we overlap the data for the next sequence
400   if (start + num_entities > (*i)->data()->start_handle()) {
401     data_out = (*i)->data();
402     if ((*i)->values_per_entity() != values_per_ent)
403       return false;
404     // If overlap, must be entirely contained
405     return start >= data_out->start_handle() &&
406            start + num_entities - 1 <= data_out->end_handle();
407   }
408 
409   // Check if we overlap the data for the previous sequence
410   if (i != begin()) {
411     --i;
412     if ((*i)->data()->end_handle() >= start) {
413       data_out = (*i)->data();
414       if ((*i)->values_per_entity() != values_per_ent)
415         return false;
416       return start + num_entities - 1 <= (*i)->data()->end_handle();
417     }
418   }
419 
420   // Unused handle block that overlaps no SequenceData
421   return true;
422 }
423 
find_free_block(EntityID num_entities,EntityHandle min_start_handle,EntityHandle max_end_handle)424 EntityHandle TypeSequenceManager::find_free_block(EntityID num_entities,
425                                                   EntityHandle min_start_handle,
426                                                   EntityHandle max_end_handle)
427 {
428   const_iterator i = lower_bound(min_start_handle);
429   if (i == end())
430     return min_start_handle;
431 
432   if ((*i)->start_handle() < min_start_handle + num_entities)
433     return min_start_handle;
434 
435   EntityHandle prev_end = (*i)->end_handle(); ++i;
436   for (; i != end(); prev_end = (*i)->end_handle(), ++i) {
437     EntityID len = (*i)->start_handle() - prev_end - 1;
438     if (len >= num_entities)
439       break;
440   }
441 
442   if (prev_end + num_entities > max_end_handle)
443     return 0;
444   else
445     return prev_end + 1;
446 }
447 
448 struct range_data {
449   EntityID num_entities;
450   EntityHandle min_start_handle, max_end_handle;
451   EntityHandle first, last;
452 };
453 
check_range(const range_data & d,bool prefer_end,EntityHandle & result)454 static bool check_range(const range_data& d,
455                         bool prefer_end,
456                         EntityHandle& result)
457 {
458   EntityHandle first = std::max(d.min_start_handle, d.first);
459   EntityHandle  last = std::min(d.max_end_handle, d.last);
460   if (last < first + d.num_entities - 1) {
461     result = 0;
462     return false;
463   }
464 
465   result = prefer_end ? last + 1 - d.num_entities : first;
466   return true;
467 }
468 
find_free_sequence(EntityID num_entities,EntityHandle min_start_handle,EntityHandle max_end_handle,SequenceData * & data_out,EntityID & data_size,int num_verts)469 EntityHandle TypeSequenceManager::find_free_sequence(EntityID num_entities,
470                                                      EntityHandle min_start_handle,
471                                                      EntityHandle max_end_handle,
472                                                      SequenceData*& data_out,
473                                                      EntityID &data_size,
474                                                      int num_verts)
475 {
476   if (max_end_handle < min_start_handle + num_entities - 1)
477     return 0;
478 
479   EntityHandle result;
480   iterator p, i = lower_bound(min_start_handle);
481   range_data d = {num_entities, min_start_handle, max_end_handle, 0, 0};
482 
483   if (i == end()) {
484     data_out = 0;
485     return min_start_handle;
486   }
487   else if (i == begin()) {
488     if ((*i)->values_per_entity() == num_verts) {
489       d.first = (*i)->data()->start_handle();
490       d.last  = (*i)->start_handle() - 1;
491       if (check_range(d, true, result)) {
492         data_out = (*i)->data();
493         return result;
494       }
495     }
496     d.first = min_start_handle;
497     d.last = (*i)->data()->start_handle() - 1;
498     if (check_range(d, true, result)) {
499       data_out = 0;
500       // This will back up against the end of the seq data, so
501       // size the data that way
502       data_size = num_entities;
503       return result;
504     }
505     p = i++;
506   }
507   else {
508     p = i;
509     --p;
510   }
511 
512   for (; i != end() && (*i)->start_handle() < max_end_handle; p = i++) {
513     if ((*p)->data() == (*i)->data()) {
514       if ((*p)->values_per_entity() == num_verts) {
515         d.first = (*p)->end_handle() + 1;
516         d.last = (*i)->start_handle() - 1;
517         if (check_range(d, false, result)) {
518           data_out = (*p)->data();
519           return result;
520         }
521       }
522     }
523     else {
524       if ((*p)->values_per_entity() == num_verts) {
525         d.first = (*p)->end_handle() + 1;
526         d.last = (*p)->data()->end_handle();
527         if (check_range(d, false, result)) {
528           data_out = (*p)->data();
529           return result;
530         }
531       }
532       if ((*i)->values_per_entity() == num_verts) {
533         d.first = (*i)->data()->start_handle();
534         d.last = (*i)->start_handle() - 1;
535         if (check_range(d, true, result)) {
536           data_out = (*i)->data();
537           return result;
538         }
539       }
540       d.first = (*p)->data()->end_handle() + 1;
541       d.last  = (*i)->data()->start_handle() - 1;
542       if (check_range(d, false, result)) {
543         data_out = 0;
544         data_size = d.last - d.first + 1;
545         return result;
546       }
547     }
548   }
549 
550   if ((*p)->values_per_entity() == num_verts) {
551     d.first = (*p)->end_handle() + 1;
552     d.last = (*p)->data()->end_handle();
553     if (check_range(d, false, result)) {
554       data_out = (*p)->data();
555       return result;
556     }
557   }
558 
559   d.first = (*p)->data()->end_handle() + 1;
560   d.last = max_end_handle;
561   if (check_range(d, false, result)) {
562     data_out = 0;
563     return result;
564   }
565 
566   data_out = 0;
567   return 0;
568 }
569 
last_free_handle(EntityHandle after_this) const570 EntityHandle TypeSequenceManager::last_free_handle(EntityHandle after_this) const
571 {
572   int junk;
573   const_iterator it = lower_bound(after_this);
574   if (it == end())
575     return CREATE_HANDLE(TYPE_FROM_HANDLE(after_this), MB_END_ID, junk);
576   else if ((*it)->start_handle() > after_this) {
577     // Need to check against the sequence data first
578     EntityHandle rhandle = (*it)->data()->start_handle();
579     return rhandle - 1;
580   }
581   else
582     return 0;
583 }
584 
check_valid_handles(Error *,EntityHandle first,EntityHandle last) const585 ErrorCode TypeSequenceManager::check_valid_handles(Error* /* error_handler */,
586                                                    EntityHandle first,
587                                                    EntityHandle last) const
588 {
589   const_iterator i = lower_bound(first);
590   if (i == end() || (*i)->start_handle() > first) {
591 #if 0
592     // MB_ENTITY_NOT_FOUND could be a non-error condition, do not call
593     // MB_SET_ERR on it
594     fprintf(
595       stderr,
596       "[Warning]: Invalid entity handle: 0x%lx\n", (unsigned long)first
597       );
598 #endif
599     return MB_ENTITY_NOT_FOUND;
600   }
601 
602   while ((*i)->end_handle() < last) {
603     EntityHandle prev_end = (*i)->end_handle();
604     ++i;
605     if (i == end() || prev_end + 1 != (*i)->start_handle())
606       return MB_ENTITY_NOT_FOUND;
607   }
608 
609   return MB_SUCCESS;
610 }
611 
erase(Error *,EntityHandle h)612 ErrorCode TypeSequenceManager::erase(Error* /* error_handler */, EntityHandle h)
613 {
614   EntitySequence* seq = find(h);
615   if (!seq) {
616 #if 0
617     // MB_ENTITY_NOT_FOUND could be a non-error condition, do not call
618     // MB_SET_ERR on it
619     fprintf(
620       stderr,
621       "[Warning]: Invalid entity handle: 0x%lx\n", (unsigned long)h
622       );
623 #endif
624     return MB_ENTITY_NOT_FOUND;
625   }
626 
627   if (seq->start_handle() == h) {
628     if (seq->end_handle() != h) {
629       if (seq->using_entire_data())
630         availableList.insert(seq->data());
631       seq->pop_front(1);
632       return MB_SUCCESS;
633     }
634     SequenceData* data = seq->data();
635     bool delete_data;
636     ErrorCode rval = remove_sequence(seq, delete_data);
637     if (MB_SUCCESS != rval)
638       return rval;
639     delete seq;
640     if (delete_data)
641       delete data;
642   }
643   else if (seq->end_handle() == h) {
644     if (seq->using_entire_data())
645       availableList.insert(seq->data());
646     seq->pop_back(1);
647   }
648   else {
649     iterator i = lower_bound(h);
650     if ((*i)->using_entire_data())
651       availableList.insert((*i)->data());
652     i = split_sequence(i, h);
653     seq = *i;
654     assert(seq->start_handle() == h);
655     seq->pop_front(1);
656   }
657 
658   return MB_SUCCESS;
659 }
660 
erase(Error *,EntityHandle first,EntityHandle last)661 ErrorCode TypeSequenceManager::erase(Error* /* error */, EntityHandle first, EntityHandle last)
662 {
663   // First check that all entities in range are valid
664 
665   ErrorCode rval = check_valid_handles(NULL, first, last);
666   if (MB_SUCCESS != rval)
667     return rval;
668 
669   // Now remove entities
670 
671   // Get first sequence intersecting range
672   iterator i = lower_bound(first);
673   if (i == end()) // Shouldn't be possible given check_valid_handles call above.
674     return MB_ENTITY_NOT_FOUND;
675 
676   // If range is entirely in interior of sequence, need to split sequence.
677   if ((*i)->start_handle() < first && (*i)->end_handle() > last) {
678     if ((*i)->using_entire_data())
679       availableList.insert((*i)->data());
680     i = split_sequence(i, first);
681     (*i)->pop_front(last - first + 1);
682     assert(check_valid_data(*i));
683     return MB_SUCCESS;
684   }
685 
686   // If range doesn't entirely contain first sequence, remove some
687   // handles from the end of the sequence and advance to the next
688   // sequence.
689   if ((*i)->start_handle() < first) {
690     if ((*i)->using_entire_data())
691       availableList.insert((*i)->data());
692     (*i)->pop_back((*i)->end_handle() - first + 1);
693     ++i;
694   }
695 
696   // Destroy all sequences contained entirely within the range
697   while (i != end() && (*i)->end_handle() <= last)
698     i = erase(i);
699 
700   // If necessary, remove entities from the beginning of the
701   // last sequence.
702   if (i != end() && (*i)->start_handle() <= last) {
703     if ((*i)->using_entire_data())
704       availableList.insert((*i)->data());
705     (*i)->pop_front(last - (*i)->start_handle() + 1);
706     assert(check_valid_data(*i));
707   }
708 
709   return MB_SUCCESS;
710 }
711 
split_sequence(iterator i,EntityHandle h)712 TypeSequenceManager::iterator TypeSequenceManager::split_sequence(iterator i, EntityHandle h)
713 {
714   EntitySequence* seq = (*i)->split(h);
715   if (!seq)
716     return end();
717 
718   i = sequenceSet.insert(i, seq);
719   assert(check_valid_data(*i));
720 
721   return i;
722 }
723 
is_free_handle(EntityHandle handle,iterator & seq_iter_out,SequenceData * & data_ptr_out,EntityHandle & block_start,EntityHandle & block_end,int values_per_ent)724 ErrorCode TypeSequenceManager::is_free_handle(EntityHandle handle,
725                                               iterator& seq_iter_out,
726                                               SequenceData*& data_ptr_out,
727                                               EntityHandle& block_start,
728                                               EntityHandle& block_end,
729                                               int values_per_ent)
730 {
731   int junk;
732   block_start = CREATE_HANDLE(TYPE_FROM_HANDLE(handle), MB_START_ID, junk);
733   block_end   = CREATE_HANDLE(TYPE_FROM_HANDLE(handle), MB_END_ID,   junk);
734 
735   iterator i = lower_bound(handle);
736   if (i != end()) {
737     block_end = (*i)->start_handle() - 1;
738 
739     // If sequence contains handle, then already allocated
740     if ((*i)->start_handle() <= handle)
741       return MB_ALREADY_ALLOCATED;
742 
743     // Handle is not within an existing sequence, but is
744     // within an existing SequenceData...
745     if ((*i)->data()->start_handle() <= handle) {
746       // If values_per_entity don't match, can't put new entity
747       // in existing SequenceData
748       if ((*i)->values_per_entity() != values_per_ent)
749         return MB_ALREADY_ALLOCATED;
750 
751       data_ptr_out = (*i)->data();
752       if (block_end == handle) {
753         // Prepend to existing sequence
754         seq_iter_out = i;
755         block_start = handle;
756       }
757       else {
758         // Add new sequence to existing SequenceData
759         seq_iter_out = end();
760         if (i == begin() || (*--i)->data() != data_ptr_out)
761           block_start = data_ptr_out->start_handle();
762         else
763           block_start = (*i)->end_handle() + 1;
764       }
765       return MB_SUCCESS;
766     }
767   }
768 
769   if (i != begin()) {
770     --i;
771     block_start = (*i)->end_handle() + 1;
772 
773     // Handle is within previous sequence data...
774     if ((*i)->data()->end_handle() >= handle) {
775       // If values_per_entity don't match, can't put new entity
776       // in existing SequenceData
777       if ((*i)->values_per_entity() != values_per_ent)
778         return MB_ALREADY_ALLOCATED;
779 
780       data_ptr_out = (*i)->data();
781       if (block_start == handle) {
782         // Append to existing sequence
783         seq_iter_out = i;
784         block_end = handle;
785       }
786       else {
787         // Add new sequence to existing SequenceData
788         seq_iter_out = end();
789         if (++i == end() || (*i)->data() != data_ptr_out)
790           block_end = data_ptr_out->end_handle();
791         else
792           block_end = (*i)->start_handle() - 1;
793       }
794       return MB_SUCCESS;
795     }
796   }
797 
798   seq_iter_out = end();
799   data_ptr_out = 0;
800 
801   return MB_SUCCESS;
802 }
803 
notify_appended(iterator seq)804 ErrorCode TypeSequenceManager::notify_appended(iterator seq)
805 {
806   ErrorCode rval = check_merge_next(seq);
807   if ((*seq)->using_entire_data())
808     availableList.erase((*seq)->data());
809 
810   return rval;
811 }
812 
notify_prepended(iterator seq)813 ErrorCode TypeSequenceManager::notify_prepended(iterator seq)
814 {
815   ErrorCode rval = check_merge_prev(seq);
816   if ((*seq)->using_entire_data())
817     availableList.erase((*seq)->data());
818 
819   return rval;
820 }
821 
get_memory_use(unsigned long long & entity_storage,unsigned long long & total_storage) const822 void TypeSequenceManager::get_memory_use(unsigned long long& entity_storage,
823                                          unsigned long long& total_storage) const
824 {
825   entity_storage = total_storage = 0;
826   if (empty())
827     return;
828 
829   EntityType mytype = TYPE_FROM_HANDLE(lastReferenced->start_handle());
830   int junk;
831   get_memory_use(CREATE_HANDLE(mytype, MB_START_ID, junk),
832                  CREATE_HANDLE(mytype, MB_END_ID,   junk),
833                  entity_storage,
834                  total_storage);
835 }
836 
append_memory_use(EntityHandle first,EntityHandle last,const SequenceData * data,unsigned long long & entity_storage,unsigned long long & total_storage) const837 void TypeSequenceManager::append_memory_use(EntityHandle first,
838                                             EntityHandle last,
839                                             const SequenceData* data,
840                                             unsigned long long& entity_storage,
841                                             unsigned long long& total_storage) const
842 {
843   const unsigned long allocated_count = data->size();
844 
845   unsigned long bytes_per_ent, seq_size;
846   const_iterator i = data->seqManData.firstSequence;
847   (*i)->get_const_memory_use(bytes_per_ent, seq_size);
848 
849   unsigned long other_ent_mem = 0;
850   unsigned long occupied_count = 0, entity_count = 0, sequence_count = 0;
851   for (; i != end() && (*i)->data() == data; ++i) {
852     occupied_count += (*i)->size();
853     ++sequence_count;
854 
855     EntityHandle start = std::max(first, (*i)->start_handle());
856     EntityHandle  stop = std::min(last, (*i)->end_handle());
857     if (stop < start)
858       continue;
859 
860     entity_count += stop - start + 1;
861     other_ent_mem += (*i)->get_per_entity_memory_use(start, stop);
862   }
863 
864   unsigned long sum = sequence_count * seq_size +
865                       allocated_count * bytes_per_ent;
866 
867   // Watch for overflow
868   assert(entity_count > 0 && occupied_count > 0 && allocated_count > 0);
869   if (std::numeric_limits<unsigned long>::max() / entity_count <= sum) {
870     total_storage  += sum * (entity_count /  occupied_count) + other_ent_mem;
871     entity_storage += sum * (entity_count / allocated_count) + other_ent_mem;
872   }
873   else {
874     total_storage  += sum * entity_count /  occupied_count + other_ent_mem;
875     entity_storage += sum * entity_count / allocated_count + other_ent_mem;
876   }
877 }
878 
get_memory_use(EntityHandle first,EntityHandle last,unsigned long long & entity_storage,unsigned long long & total_storage) const879 void TypeSequenceManager::get_memory_use(EntityHandle first,
880                                          EntityHandle last,
881                                          unsigned long long& entity_storage,
882                                          unsigned long long& total_storage) const
883 {
884   entity_storage = total_storage = 0;
885 
886   while (first <= last) {
887     const_iterator i = lower_bound(first);
888     if (i == end())
889       return;
890 
891     SequenceData* data = (*i)->data();
892     if (first < data->end_handle()) {
893       append_memory_use(first, last, data, entity_storage, total_storage);
894     }
895     first  = data->end_handle() + 1;
896   }
897 }
898 
get_occupied_size(const SequenceData * data) const899 EntityID TypeSequenceManager::get_occupied_size(const SequenceData* data) const
900 {
901   EntityID result = 0;
902   for (const_iterator i = data->seqManData.firstSequence; i != end() && (*i)->data() == data; ++i)
903     result += (*i)->size();
904 
905   return result;
906 }
907 
908 #ifndef NDEBUG
check_valid_data(const EntitySequence * seq) const909 bool TypeSequenceManager::check_valid_data(const EntitySequence* seq) const
910 {
911   // Caller passed a sequence that should be contained, so cannot be empty
912   if (empty())
913     return false;
914 
915   // Make sure lastReferenced points to something
916   if (!lastReferenced)
917     return false;
918 
919   const_iterator seqi = sequenceSet.lower_bound(lastReferenced);
920   if (seqi == sequenceSet.end() || *seqi != lastReferenced)
921     return false;
922 
923   // Make sure passed sequence is in list
924   const EntitySequence* seq2 = find(seq->start_handle());
925   if (seq2 != seq)
926     return false;
927 
928   // Check all sequences referencing the same SequenceData
929   const SequenceData* data = seq->data();
930   const_iterator i = lower_bound(data->start_handle());
931   if (i != data->seqManData.firstSequence)
932     return false;
933 
934   if (i != begin()) {
935     const_iterator j = i;
936     --j;
937     if ((*j)->end_handle() >= data->start_handle())
938       return false;
939     if ((*j)->data()->end_handle() >= data->start_handle())
940       return false;
941   }
942 
943   for (;;) {
944     seq2 = *i;
945     ++i;
946     if (i == end())
947       return true;
948     if ((*i)->data() != data)
949       break;
950 
951     if (seq2->end_handle() >= (*i)->start_handle())
952       return false;
953   }
954 
955   if ((*i)->start_handle() <= data->end_handle())
956     return false;
957   if ((*i)->data()->start_handle() <= data->end_handle())
958     return false;
959 
960   return true;
961 }
962 
963 #endif
964 
965 } // namespace moab
966