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