Loading...
Searching...
No Matches
piercedKernel.tpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#ifndef __BITPIT_PIERCED_KERNEL_TPP__
26#define __BITPIT_PIERCED_KERNEL_TPP__
27
28namespace bitpit {
29
30// Definition of static constants of PiercedKernel
31template<typename id_t>
32const std::size_t PiercedKernel<id_t>::MAX_PENDING_HOLES = 16384;
33
37template<typename id_t>
43
50template<typename id_t>
53{
54 clear();
55
56 reserve(n);
57}
58
62template<typename id_t>
64{
65 for (PiercedStorageSyncSlave<id_t> *storage : getStorages()) {
66 storage->unsetKernel();
67 }
68}
69
76template<typename id_t>
77void PiercedKernel<id_t>::updateId(const id_t &currentId, const id_t &updatedId)
78{
79 // Validate the id
80 validateId(updatedId);
81
82 // Update the id
83 setPosId(getPos(currentId), updatedId);
84 m_pos.erase(currentId);
85}
86
93template<typename id_t>
95{
96 ClearAction syncAction = _clear(release);
97
98 // Update the storage
99 processSyncAction(syncAction);
100
101 return syncAction;
102}
103
104
113template<typename id_t>
115{
116 // Clear positions
117 m_ids.clear();
118 m_pos.clear();
119 if (release) {
120 std::vector<id_t>().swap(m_ids);
121 std::unordered_map<id_t, std::size_t, PiercedHasher>().swap(m_pos);
122 }
123
124 // Reset begin and end
125 setBeginPos(0);
126 setEndPos(0);
127
128 // Clear holes
129 holesClear(release);
130
131 // There are no dirty positions
132 m_dirty_begin_pos = m_end_pos;
133
134 // Generate the sync action
135 ClearAction syncAction;
136
137 return syncAction;
138}
139
152template<typename id_t>
154{
155 ReserveAction syncAction = _reserve(n);
156
157 // Update the storage
158 processSyncAction(syncAction);
159
160 return syncAction;
161}
162
177template<typename id_t>
179{
180 // Update the kernel
181 m_ids.reserve(n);
182 m_pos.reserve(n);
183
184 // Generate the sync action
185 ReserveAction syncAction;
186 syncAction.info[PiercedSyncAction::INFO_SIZE] = n;
187
188 return syncAction;
189}
190
208template<typename id_t>
210{
211 ResizeAction syncAction = _resize(n);
212
213 // Update the storage
214 processSyncAction(syncAction);
215
216 return syncAction;
217}
218
238template<typename id_t>
240{
241 // If the size of the kernel is already the requested size there is
242 // nothing to do.
243 if (n == size()) {
244 ResizeAction syncAction(ResizeAction::TYPE_NOOP);
245
246 return syncAction;
247 }
248
249 // A request for a size equal to 0 is equivalent to a clear.
250 if (n == 0) {
251 _clear();
252
253 ResizeAction syncAction(ResizeAction::TYPE_CLEAR);
254
255 return syncAction;
256 }
257
258 // If the requested size is greater that the current size we may need to
259 // reserve space to allow the kernel to reach the requested size.
260 if (n > size()) {
261 _reserve(n);
262
263 ResizeAction syncAction(ResizeAction::TYPE_RESERVE);
264 syncAction.info[PiercedSyncAction::INFO_SIZE] = rawSize();
265
266 return syncAction;
267 }
268
269 // If the requested size is smaller that the current size
270 // we need to perform a real resize.
271
272 // Flush holes
273 holesFlush();
274
275 // Find the id of the last element
276 id_t last_stored_id = getSizeMarker(n - 1);
277
278 // Find the last position
279 std::size_t last_used_pos = getPos(last_stored_id);
280
281 // Shrink the kernel
282 rawShrink(last_used_pos + 1);
283
284 // Generate the sync action
285 ResizeAction syncAction(ResizeAction::TYPE_RESIZE);
286 syncAction.info[PiercedSyncAction::INFO_SIZE] = rawSize();
287
288 return syncAction;
289}
290
294template<typename id_t>
296{
297 SortAction syncAction = _sort(m_begin_pos, m_end_pos);
298
299 // Update the storage
300 processSyncAction(syncAction);
301
302 return syncAction;
303}
304
314template<typename id_t>
315typename PiercedKernel<id_t>::SortAction PiercedKernel<id_t>::sortAfter(id_t referenceId, bool inclusive)
316{
317 // Get the reference position
318 std::size_t referencePos = getPos(referenceId);
319 if (!inclusive) {
320 referencePos++;
321 }
322
323 // Sorte the
324 SortAction syncAction = _sort(referencePos, m_end_pos);
325
326 // Update the storage
327 processSyncAction(syncAction);
328
329 return syncAction;
330}
331
341template<typename id_t>
342typename PiercedKernel<id_t>::SortAction PiercedKernel<id_t>::sortBefore(id_t referenceId, bool inclusive)
344 // Get the reference position
345 std::size_t referencePos = getPos(referenceId);
346 if (inclusive) {
347 referencePos++;
348 }
350 // Sort the container
351 SortAction syncAction = _sort(m_begin_pos, referencePos);
353 // Update the storage
354 processSyncAction(syncAction);
356 return syncAction;
367template<typename id_t>
368typename PiercedKernel<id_t>::SortAction PiercedKernel<id_t>::_sort(std::size_t beginPos, std::size_t endPos)
370 // Squeeze the kernel
371 //
372 // After the squeeze there will be no holes in the kernel.
373 SqueezeAction squeezeAction = _squeeze();
374 const std::vector<std::size_t> &squeezePermutations = *(squeezeAction.data);
375 bool squeezed = (squeezeAction.data.get() != nullptr);
377 // Get updated kernel size
378 std::size_t updatedKernelRawSize = rawSize();
379
380 // Update the sort range
381 if (squeezed) {
382 std::size_t previousBeginPos = beginPos;
383 std::size_t previousEndPos = endPos;
384 for (std::size_t i = m_begin_pos; i < m_end_pos; ++i) {
385 std::size_t previousPos = squeezePermutations[i];
386 if (previousPos == previousBeginPos) {
387 beginPos = i;
389 if ((previousPos + 1) == previousEndPos) {
390 endPos = i + 1;
391 break;
392 }
393 }
395
396 // Evaluates the sort permutations
397 std::vector<std::size_t> sortPermutations(updatedKernelRawSize);
398 for (std::size_t i = 0; i < updatedKernelRawSize; ++i) {
399 sortPermutations[i] = i;
402 std::sort(sortPermutations.begin() + beginPos, sortPermutations.begin() + endPos, idLess(m_ids));
404 // Create the sync action
405 SortAction syncAction;
406 syncAction.info[PiercedSyncAction::INFO_SIZE] = updatedKernelRawSize;
407 if (squeezed) {
408 syncAction.importData(std::vector<std::size_t>(squeezePermutations));
409 std::vector<std::size_t> &permutations = *(syncAction.data);
410 for (std::size_t i = beginPos; i < endPos; ++i) {
411 permutations[i] = squeezePermutations[sortPermutations[i]];
413 } else {
414 syncAction.importData(std::vector<std::size_t>(sortPermutations));
415 }
417 // Sort the ids
418 //
419 // NOTE: the reorder function will destroy the permutation vector
420 utils::reorderVector<id_t>(sortPermutations, m_ids, updatedKernelRawSize);
421
422 // Update the positions
423 m_pos.clear();
424 for (std::size_t i = 0; i < updatedKernelRawSize; ++i) {
425 m_pos[m_ids[i]] = i;
426 }
427
428 // Return the permutations
429 return syncAction;
430}
431
442template<typename id_t>
445 SqueezeAction syncAction = _squeeze();
446
447 // Update the storage
448 processSyncAction(syncAction);
450 return syncAction;
465template<typename id_t>
467{
468 // Flush changes
469 flush();
470
471 // Sort the holes
472 //
473 // After being flushed, the container will contain only regular holes.
474 holesSortRegular();
475
476 // Get kernel size
477 std::size_t kernelSize = size();
478 std::size_t kernelRawSize = rawSize();
479
480 // Initialize the sync action
481 SqueezeAction syncAction;
482 syncAction.info[PiercedSyncAction::INFO_SIZE] = kernelSize;
483
484 // Compact the kernel
485 std::size_t nHoles = holesCount();
486 if (nHoles != 0) {
487 // Initialize sync data
488 syncAction.importData(std::vector<std::size_t>(kernelRawSize));
489 std::vector<std::size_t> &permutations = *(syncAction.data);
490
491 // Move the elements
492 std::size_t firstPosToUpdate;
493 if (m_begin_pos == 0) {
494 firstPosToUpdate = m_holes[m_holes_regular_end - 1];
495 } else {
496 firstPosToUpdate = 0;
497 }
498
499 for (std::size_t pos = 0; pos < firstPosToUpdate; ++pos) {
500 permutations[pos] = pos;
501 }
502
503 std::size_t offset = 0;
504 for (std::size_t pos = firstPosToUpdate; pos < m_end_pos; pos++) {
505 if (offset < nHoles && m_holes[m_holes_regular_end - offset - 1] == pos) {
506 permutations[m_end_pos - 1 - offset] = pos;
507 ++offset;
508 continue;
509 }
510
511 id_t id = m_ids[pos];
512 std::size_t updatedPos = pos - offset;
513
514 setPosId(updatedPos, id);
515 setPosEmptyId(pos, pos + 1);
516 permutations[updatedPos] = pos;
517 }
518
519 for (std::size_t pos = m_end_pos; pos < rawSize(); ++pos) {
520 permutations[pos] = pos;
521 }
522
523 // Clear the holes
524 holesClear(true);
525
526 // Reset begin position
527 setBeginPos(0);
528
529 // Shrink the kernel
530 rawShrink(kernelSize);
531 }
532
533 // Shrink to fit
534 _shrinkToFit();
535
536 return syncAction;
537}
538
549template<typename id_t>
551{
552 ShrinkToFitAction syncAction = _shrinkToFit();
553
554 // Update the storage
555 processSyncAction(syncAction);
556
557 return syncAction;
558}
559
572template<typename id_t>
574{
575 // Update the kernel
576 m_ids.shrink_to_fit();
577
578 // Generate the sync action
579 ShrinkToFitAction syncAction;
580
581 return syncAction;
582}
583
596template<typename id_t>
598{
600
601 std::swap(other.m_begin_pos, m_begin_pos);
602 std::swap(other.m_end_pos, m_end_pos);
603 std::swap(other.m_dirty_begin_pos, m_dirty_begin_pos);
604 std::swap(other.m_ids, m_ids);
605 std::swap(other.m_pos, m_pos);
606 std::swap(other.m_holes, m_holes);
607 std::swap(other.m_holes_regular_begin, m_holes_regular_begin);
608 std::swap(other.m_holes_regular_end, m_holes_regular_end);
609 std::swap(other.m_holes_regular_sorted, m_holes_regular_sorted);
610 std::swap(other.m_holes_pending_begin, m_holes_pending_begin);
611 std::swap(other.m_holes_pending_end, m_holes_pending_end);
612 std::swap(other.m_holes_pending_sorted, m_holes_pending_sorted);
613}
614
618template<typename id_t>
620{
621 // Flush pending holes
622 holesFlush();
623}
624
628template<typename id_t>
630{
631 std::cout << "----------------[ DUMP ]----------------" << std::endl;
632
633 std::cout << std::endl;
634 std::cout << " size: " << size() << std::endl;
635
636 std::cout << " m_holes_regular_begin: " << m_holes_regular_begin << std::endl;
637 std::cout << " m_holes_regular_end : " << m_holes_regular_end << std::endl;
638
639 std::cout << std::endl;
640 std::cout << " Regular holes: " << std::endl;
641 for (std::size_t k = m_holes_regular_begin; k < m_holes_regular_end; ++k) {
642 std::cout << m_holes[k] << std::endl;
643 }
644
645 std::cout << std::endl;
646 std::cout << " m_holes_pending_begin: " << m_holes_pending_begin << std::endl;
647 std::cout << " m_holes_pending_end : " << m_holes_pending_end << std::endl;
648
649 std::cout << std::endl;
650 std::cout << " Pending holes" << std::endl;
651 for (std::size_t k = m_holes_pending_begin; k < m_holes_pending_end; ++k) {
652 std::cout << m_holes[k] << std::endl;
653 }
654
655 std::cout << std::endl;
656 std::cout << " m_begin_pos: " << m_begin_pos << std::endl;
657 std::cout << " m_end_pos: " << m_end_pos << std::endl;
658 std::cout << " Stored ids: " << std::endl;
659 if (rawSize() > 0) {
660 for (std::size_t k = 0; k < m_end_pos; ++k) {
661 std::cout << m_ids[k] << std::endl;
662 }
663 } else {
664 std::cout << "None" << std::endl;
665 }
666
667 std::cout << std::endl;
668 std::cout << " Poistion map: " << std::endl;
669 if (size() > 0) {
670 for (auto itr = m_pos.cbegin(); itr != m_pos.cend(); ++itr) {
671 std::cout << itr->first << " -> " << itr->second << std::endl;
672 }
673 } else {
674 std::cout << "None" << std::endl;
675 }
676
677 std::cout << "----------------------------------------" << std::endl;
678}
679
683template<typename id_t>
685{
686 // Check if the elements and their position match
687 for (const auto &entry : m_pos) {
688 id_t id = entry.first;
689 std::size_t pos = entry.second;
690 if (m_ids[pos] != id) {
691 std::cout << " Position " << pos << " should contain the element with id " << id << std::endl;
692 std::cout << " but it contains the element with id " << m_ids[pos] << std::endl;
693 throw std::runtime_error("Integrity check error");
694 }
695 }
696
697 for (std::size_t pos = m_begin_pos; pos < m_end_pos; ++pos) {
698 id_t id = m_ids[pos];
699 if (id >= 0) {
700 if (m_pos.count(id) == 0) {
701 std::cout << " Position " << pos << " contains the element with id " << id << std::endl;
702 std::cout << " but the position map doesn't contain that element" << std::endl;
703 throw std::runtime_error("Integrity check error");
704 } else if (m_pos.at(id) != pos) {
705 std::cout << " Position " << pos << " contains the element with id " << id << std::endl;
706 std::cout << " but the position map claims that the element is at position " << m_pos.at(id) << std::endl;
707 throw std::runtime_error("Integrity check error");
708 }
709 }
710 }
711
712 // Check if the number of elements visited by the iterator matches the size of the kernel
713 std::size_t n = 0;
714 for (auto it = begin(); it != end(); ++it) {
715 ++n;
716 }
717
718 if (n != size()) {
719 std::cout << " The number of elements visited by the iterator doesn't match the size of the kernel" << std::endl;
720 std::cout << " The iterator has visited " << n << "elements" << std::endl;
721 std::cout << " The size of the kernel is " << size() << std::endl;
722 throw std::runtime_error("Integrity check error");
723 }
724
725 // Check the consistency of the ids of elements associated with empty positions
726 //
727 // The id of an empty element contains the distance, measured in number of elements, between
728 // the current element and the next element the iterator should jump to (the distance is
729 // negative). If the id of an element is lower than -1, the ids of the following elements
730 // should be consecutive until they reach -1.
731 if (!empty()) {
732 std::size_t pos = 0;
733 while (pos < m_ids.size() - 1) {
734 for (std::size_t i = pos; i < m_ids.size(); ++i) {
735 // Skip non-empty positions
736 if (m_ids[i] >= 0) {
737 pos = i + 1;
738 break;
739 }
740
741 // Skip empty positions with a distance from a non-empty element equal to one
742 if (m_ids[i + 1] >= 0 && m_ids[i] == - 1) {
743 pos = i + 2;
744 break;
745 }
746
747 // Check if ids are consecutive
748 if ((m_ids[i] - m_ids[i + 1] != -1) && m_ids[i] != -1) {
749 std::cout << " The ids associated with empty positions are not consecutive" << std::endl;
750 std::cout << " Position " << i << " is associated with id " << m_ids[i] << std::endl;
751 std::cout << " Position " << (i + 1) << " is associated with id " << m_ids[i + 1] << std::endl;
752 throw std::runtime_error("Integrity check error");
753 }
754 }
755 }
756 }
757}
758
765template<typename id_t>
767{
768 return (holesCount() == 0);
769}
770
776template<typename id_t>
778{
779 return m_pos.empty();
780}
781
794template<typename id_t>
796{
797 return (m_dirty_begin_pos < m_end_pos);
798}
799
808template<typename id_t>
810{
811 return m_ids.max_size();
812}
813
822template<typename id_t>
823std::size_t PiercedKernel<id_t>::size() const
824{
825 return m_pos.size();
826}
827
836template<typename id_t>
838{
839 return m_ids.size();
840}
841
849template<typename id_t>
851{
852 return m_ids.capacity();
853}
854
862template<typename id_t>
864{
865 return (m_pos.count(id) != 0);
866}
867
879template<typename id_t>
880std::size_t PiercedKernel<id_t>::count(id_t id) const
881{
882 return m_pos.count(id);
883}
884
890template<typename id_t>
891std::size_t PiercedKernel<id_t>::getRawIndex(id_t id) const
892{
893 return getPos(id);
894}
895
911template<typename id_t>
912std::size_t PiercedKernel<id_t>::evalFlatIndex(id_t id) const
913{
914 std::size_t pos = getPos(id);
915
916 // Initialize flat id with the position of the element
917 std::size_t flat = pos;
918
919 // Subtract pending holes before position
920 if (holesCountPending() > 0) {
921 holes_const_iterator pending_begin_itr = m_holes.cbegin() + m_holes_pending_begin;
922 holes_const_iterator pending_end_itr = m_holes.cbegin() + m_holes_pending_end;
923
924 std::size_t nHolesBefore = 0;
925 for (auto itr = pending_begin_itr; itr != pending_end_itr; ++itr) {
926 if (*itr <= pos) {
927 ++nHolesBefore;
928 }
929 }
930
931 flat -= nHolesBefore;
932 }
933
934 // Subtract regular holes before position
935 if (holesCountRegular() > 0) {
936 holes_const_iterator regular_begin_itr = m_holes.cbegin() + m_holes_regular_begin;
937 holes_const_iterator regular_end_itr = m_holes.cbegin() + m_holes_regular_end;
938
939 std::size_t nHolesBefore = 0;
940 for (auto itr = regular_begin_itr; itr != regular_end_itr; ++itr) {
941 if (*itr <= pos) {
942 ++nHolesBefore;
943 }
944 }
945
946 flat -= nHolesBefore;
947 }
948
949 // Done
950 return flat;
951}
952
960template<typename id_t>
961std::vector<id_t> PiercedKernel<id_t>::getIds(bool ordered) const
962{
963 std::size_t nIds = size();
964
965 // Initialize the vector
966 std::vector<id_t> ids;
967 if (nIds == 0) {
968 return ids;
969 }
970
971 // Resize the vector
972 ids.resize(nIds);
973
974 // Extract the ids
975 std::size_t n = 0;
976 std::size_t pos = m_begin_pos;
977 while (true) {
978 ids[n] = m_ids[pos];
979 if (n == nIds - 1) {
980 break;
981 }
982
983 n++;
984 pos = findNextUsedPos(pos);
985 }
986
987 // Sort the ids
988 if (ordered) {
989 std::sort(ids.begin(), ids.end());
990 }
991
992 return ids;
993}
994
1008template<typename id_t>
1009id_t PiercedKernel<id_t>::getSizeMarker(std::size_t targetSize, const id_t &fallback)
1010{
1011 // If the size is zero, we return the first element, if the target
1012 // size is equal to the size minus one we return the last element,
1013 // if the target size is greater or equal the current kernel size
1014 // we return the fallback value.
1015 if (targetSize >= size()) {
1016 return fallback;
1017 } else if (targetSize == 0) {
1018 return m_ids[m_begin_pos];
1019 } else if (targetSize == (size() - 1)) {
1020 return m_ids[m_end_pos - 1];
1021 }
1022
1023 // Sort the holes
1024 holesSortRegular();
1025 holesSortPending();
1026
1027 // Iterate to find the position before wihch there is the
1028 // requeste number of element.
1029 holes_iterator regular_begin_itr = m_holes.begin() + m_holes_regular_begin;
1030 holes_iterator regular_hole_itr = m_holes.begin() + m_holes_regular_end;
1031
1032 holes_iterator pending_begin_itr = m_holes.begin() + m_holes_pending_begin;
1033 holes_iterator pending_hole_itr = m_holes.begin() + m_holes_pending_end;
1034
1035 std::size_t nEmpties = 0;
1036 std::size_t markerPos = targetSize;
1037 while (true) {
1038 if (isPosEmpty(markerPos)) {
1039 markerPos = findNextUsedPos(markerPos - 1);
1040 }
1041
1042 // Count the number of holes and pending deletes before the
1043 // current marker position
1044 if (regular_hole_itr != regular_begin_itr) {
1045 holes_iterator itr_previous = regular_hole_itr;
1046 regular_hole_itr = std::upper_bound(regular_begin_itr, regular_hole_itr, markerPos, std::greater<std::size_t>());
1047 nEmpties += std::distance(regular_hole_itr, itr_previous);
1048 }
1049
1050 if (pending_hole_itr != pending_begin_itr) {
1051 holes_iterator itr_previous = pending_hole_itr;
1052 pending_hole_itr = std::upper_bound(pending_begin_itr, pending_hole_itr, markerPos, std::greater<std::size_t>());
1053 nEmpties += std::distance(pending_hole_itr, itr_previous);
1054 }
1055
1056 // Get the marker size
1057 //
1058 // If we have reached the target size we can exit, otherwise
1059 // we update the marker and we continue iterating
1060 std::size_t markerSize = markerPos - nEmpties;
1061 if (markerSize == targetSize) {
1062 break;
1063 } else {
1064 markerPos += targetSize - markerSize;
1065 }
1066 }
1067
1068 return m_ids[markerPos];
1069}
1070
1077template<typename id_t>
1079{
1080 auto iterator = m_pos.find(id);
1081 if (iterator != m_pos.end()) {
1082 return rawFind(iterator->second);
1083 } else {
1084 return end();
1085 }
1086}
1087
1094template<typename id_t>
1096{
1097 return const_iterator(this, pos);
1098}
1099
1105template<typename id_t>
1107{
1108 return cbegin();
1109}
1110
1118template<typename id_t>
1120{
1121 return cend();
1122}
1123
1129template<typename id_t>
1131{
1132 return rawFind(m_begin_pos);
1133}
1134
1141template<typename id_t>
1143{
1144 return rawFind(m_end_pos);
1145}
1146
1155template<typename id_t>
1156std::size_t PiercedKernel<id_t>::getPos(id_t id) const
1157{
1158 return m_pos.at(id);
1159}
1160
1168template<typename id_t>
1170{
1171 if (empty()) {
1172 throw std::out_of_range("Vector is empty");
1173 }
1174
1175 return m_begin_pos;
1176}
1177
1185template<typename id_t>
1187{
1188 if (empty()) {
1189 throw std::out_of_range("Vector is empty");
1190 }
1191
1192 return m_end_pos - 1;
1193}
1194
1195
1204template<typename id_t>
1206{
1207 // Check if there is a pending hole that can be filled
1208 if (m_holes_pending_begin != m_holes_pending_end) {
1209 // Sort pending holes
1210 holesSortPending();
1211
1212 // The last hole is the one with the lowest position
1213 return fillHole(m_holes_pending_end - 1, id);
1214 }
1215
1216 // Check if there is a regular hole that can be filled
1217 if (m_holes_regular_begin != m_holes_regular_end) {
1218 // Sort regular holes
1219 holesSortRegular();
1220
1221 // The last hole is the one with the lowest position
1222 return fillHole(m_holes_regular_end - 1, id);
1223 }
1224
1225 // There are no holes that can be filled
1226 return fillAppend(id);
1227}
1228
1237template<typename id_t>
1239{
1240 // Check if there is a pending hole that can be filled
1241 if (m_holes_pending_begin != m_holes_pending_end) {
1242 // Sort pending holes
1243 holesSortPending();
1244
1245 // The first hole is the one with the highest position
1246 return fillHole(m_holes_pending_begin, id);
1247 }
1248
1249 // Check if there is a regular hole that can be filled
1250 if (m_holes_regular_begin != m_holes_regular_end) {
1251 // Sort regular holes
1252 holesSortRegular();
1253
1254 // The first hole is the one with the lowest position
1255 return fillHole(m_holes_regular_begin, id);
1256 }
1257
1258 // There are no holes that can be filled
1259 return fillAppend(id);
1260}
1261
1272template<typename id_t>
1274{
1275 // Get the reference position
1276 std::size_t referencePos = getPos(referenceId);
1277
1278 // Check if there is a pending hole that can be filled
1279 if (m_holes_pending_begin != m_holes_pending_end) {
1280 // Sort pending holes
1281 holesSortPending();
1282
1283 // The first hole is the one with the highest position, if the
1284 // position of this hole is greater than the reference position
1285 // it is possible to use it.
1286 std::size_t hole = m_holes_pending_begin;
1287 if (m_holes[hole] > referencePos) {
1288 return fillHole(hole, id);
1289 }
1290 }
1291
1292 // Check if there is a regular hole that can be filled
1293 if (m_holes_regular_begin != m_holes_regular_end) {
1294 // Sort regular holes
1295 holesSortRegular();
1296
1297 // The first hole is the one with the highest position, if the
1298 // position of this hole is greater than the reference position
1299 // it is possible to use it.
1300 std::size_t hole = m_holes_regular_begin;
1301 if (m_holes[hole] > referencePos) {
1302 return fillHole(hole, id);
1303 }
1304 }
1305
1306 // There are no holes that can be filled
1307 return fillAppend(id);
1308}
1309
1320template<typename id_t>
1322{
1323 // Get the reference position
1324 std::size_t referencePos = getPos(referenceId);
1325
1326 // Check if there is a pending hole that can be filled
1327 if (m_holes_pending_begin != m_holes_pending_end) {
1328 // Sort pending holes
1329 holesSortPending();
1330
1331 // The last hole is the one with the lowest position, if the
1332 // position of this hole is greater than the reference position
1333 // it is possible to use it.
1334 std::size_t hole = m_holes_pending_end - 1;
1335 if (m_holes[hole] < referencePos) {
1336 return fillHole(hole, id);
1337 }
1338 }
1339
1340 // Check if there is a regular hole that can be filled
1341 if (m_holes_regular_begin != m_holes_regular_end) {
1342 // Sort regular holes
1343 holesSortRegular();
1344
1345 // The last hole is the one with the lowest position, if the
1346 // position of this hole is greater than the reference position
1347 // it is possible to use it.
1348 std::size_t hole = m_holes_regular_end - 1;
1349 if (m_holes[hole] < referencePos) {
1350 return fillHole(hole, id);
1351 }
1352 }
1353
1354 // There are no holes that can be filled
1355 return fillInsert(referencePos, id);
1356}
1357
1366template<typename id_t>
1368{
1369 // Check if the id is valid
1370 validateId(id);
1371
1372 // Add the id
1373 m_ids.emplace_back(id);
1374
1375 // Update last used position
1376 setEndPos(rawSize());
1377
1378 // Update the id map
1379 m_pos[id] = m_end_pos - 1;
1380
1381 // Update the storage
1382 FillAction fillAction(FillAction::TYPE_APPEND);
1383 fillAction.info[PiercedSyncAction::INFO_POS] = m_end_pos - 1;
1384 processSyncAction(fillAction);
1385
1386 // Return the fill action
1387 return fillAction;
1388}
1389
1397template<typename id_t>
1399{
1400 // Validate the id
1401 validateId(id);
1402
1403 // Get the position of the hole
1404 std::size_t pos = m_holes[hole];
1405
1406 // Fill the hole
1407 setPosId(pos, id);
1408
1409 // Remove the holes from the kernel
1410 if (hole >= m_holes_pending_begin) {
1411 int nPendings = holesCountPending();
1412 if (nPendings > 1) {
1413 if (hole == (m_holes_pending_end - 1)) {
1414 --m_holes_pending_end;
1415 } else if (hole == m_holes_pending_begin) {
1416 ++m_holes_pending_begin;
1417 } else {
1418 throw std::out_of_range("Only holes at the beginning or at the end of the kernel can be filled");
1419 }
1420 } else {
1421 holesClearPending();
1422 }
1423 } else {
1424 int nRegulars = holesCountRegular();
1425 if (nRegulars > 1) {
1426 if (hole == (m_holes_regular_end - 1)) {
1427 --m_holes_regular_end;
1428 } else if (hole == m_holes_regular_begin) {
1429 ++m_holes_regular_begin;
1430 } else {
1431 throw std::out_of_range("Only holes at the beginning or at the end of the kernel can be filled");
1432 }
1433 } else {
1434 holesClearRegular();
1435 }
1436 }
1437
1438 // Update the begin position
1439 //
1440 // There are no holes past the end of the vector, this means that only
1441 // the begin position may need an update.
1442 if (pos < m_begin_pos) {
1443 setBeginPos(pos);
1444 }
1445
1446 // Update the position of the empty elements before the current one
1447 //
1448 // It is necessary to ensure that the empty elements just before the
1449 // current one are correctly set, otherwise it will not be possible
1450 // to iterate through the kernel.
1451 std::size_t previousPos = pos;
1452 while (previousPos > 0) {
1453 --previousPos;
1454 if (!isPosEmpty(previousPos)) {
1455 break;
1456 }
1457
1458 id_t previousId = m_ids[previousPos];
1459 if (previousId == -1 || (std::size_t) std::abs(previousId) == (pos - previousPos)) {
1460 break;
1461 }
1462
1463 setPosEmptyId(previousPos, pos);
1464 }
1465
1466 // Update the storage
1467 FillAction fillAction(FillAction::TYPE_OVERWRITE);
1468 fillAction.info[PiercedSyncAction::INFO_POS] = pos;
1469 processSyncAction(fillAction);
1470
1471 // Return the fill action
1472 return fillAction;
1473}
1474
1484template<typename id_t>
1486{
1487 // If the position at which we want to insert an element is a hole there
1488 // was an error somewhere. Before inserting a new position the hole needs
1489 // to be filled first.
1490 if (isPosEmpty(pos)) {
1491 throw std::out_of_range("Before inserting a new position the hole needs to be filled first");
1492 }
1493
1494 // We cannot insert elements past the last position
1495 if (pos >= m_end_pos) {
1496 throw std::out_of_range("Unable to insert elements past the last position");
1497 }
1498
1499 // Check if the id is valid
1500 validateId(id);
1501
1502 // Add the id
1503 m_ids.emplace(m_ids.begin() + pos, id);
1504
1505 // Update last used position
1506 setEndPos(rawSize());
1507
1508 // Update the id map
1509 for (std::size_t i = pos + 1; i < m_end_pos; ++i) {
1510 id_t id_i = m_ids[i];
1511 if (id_i >= 0) {
1512 m_pos[id_i] = i;
1513 }
1514 }
1515 m_pos[id] = pos;
1516
1517 // Update the regular holes
1518 if (m_holes_regular_begin != m_holes_regular_end) {
1519 holes_iterator regular_begin_itr = m_holes.begin() + m_holes_regular_begin;
1520 holes_iterator regular_end_itr = m_holes.begin() + m_holes_regular_end;
1521
1522 holes_iterator update_begin_itr = regular_begin_itr;
1523 holes_iterator update_end_itr = upper_bound(regular_begin_itr, regular_end_itr, pos, std::greater<std::size_t>());
1524 for (auto itr = update_begin_itr; itr != update_end_itr; itr++) {
1525 (*itr)++;
1526 }
1527 }
1528
1529 // Update the pending holes
1530 if (m_holes_pending_begin != m_holes_pending_end) {
1531 holes_iterator pending_begin_itr = m_holes.begin() + m_holes_pending_begin;
1532 holes_iterator pending_end_itr = m_holes.begin() + m_holes_pending_end;
1533
1534 holes_iterator update_begin_itr = pending_begin_itr;
1535 holes_iterator update_end_itr = upper_bound(pending_begin_itr, pending_end_itr, pos, std::greater<std::size_t>());
1536 for (auto itr = update_begin_itr; itr != update_end_itr; itr++) {
1537 (*itr)++;
1538 }
1539 }
1540
1541 // Update the storage
1542 FillAction fillAction(FillAction::TYPE_INSERT);
1543 fillAction.info[PiercedSyncAction::INFO_POS] = pos;
1544 processSyncAction(fillAction);
1545
1546 // Return the fill action
1547 return fillAction;
1548}
1549
1559template<typename id_t>
1560typename PiercedKernel<id_t>::MoveAction PiercedKernel<id_t>::moveAfter(id_t referenceId, id_t id, bool flush)
1561{
1562 assert(referenceId != id);
1563
1564 // Disables the synchronization
1565 bool syncEnabled = isSyncEnabled();
1566 if (syncEnabled) {
1567 setSyncEnabled(false);
1568 }
1569
1570 // Pierce the position
1571 std::size_t initialPos = getPos(id);
1572 pierce(initialPos, flush);
1573
1574 // Insert the element in the updated position
1575 FillAction fillAction = fillAfter(referenceId, id);
1576
1577 // Re-enables the synchronization
1578 if (syncEnabled) {
1579 setSyncEnabled(true);
1580 }
1581
1582 // Update the storage
1583 typename MoveAction::MoveActionType moveActionType;
1584 switch (static_cast<typename FillAction::FillActionType>(fillAction.type)) {
1585
1586 case FillAction::TYPE_APPEND:
1587 moveActionType = MoveAction::TYPE_APPEND;
1588 break;
1589
1590 case FillAction::TYPE_INSERT:
1591 moveActionType = MoveAction::TYPE_INSERT;
1592 break;
1593
1594 case FillAction::TYPE_OVERWRITE:
1595 moveActionType = MoveAction::TYPE_OVERWRITE;
1596 break;
1597
1598 default:
1599 BITPIT_UNREACHABLE("This action is not handled");
1600 moveActionType = MoveAction::TYPE_UNDEFINED;
1601 break;
1602
1603 }
1604
1605 MoveAction moveAction(moveActionType);
1606 moveAction.info[PiercedSyncAction::INFO_POS_FIRST] = initialPos;
1607 moveAction.info[PiercedSyncAction::INFO_POS_SECOND] = fillAction.info[PiercedSyncAction::INFO_POS];
1608 processSyncAction(moveAction);
1609
1610 // Return the move action
1611 return moveAction;
1612}
1613
1623template<typename id_t>
1624typename PiercedKernel<id_t>::MoveAction PiercedKernel<id_t>::moveBefore(id_t referenceId, id_t id, bool flush)
1625{
1626 assert(referenceId != id);
1627
1628 // Disables the synchronization
1629 bool syncEnabled = isSyncEnabled();
1630 if (syncEnabled) {
1631 setSyncEnabled(false);
1632 }
1633
1634 // Pierce the position
1635 std::size_t initialPos = getPos(id);
1636 pierce(initialPos, flush);
1637
1638 // Insert the element in the updated position
1639 FillAction fillAction = fillBefore(referenceId, id);
1640
1641 // Re-enables the synchronization
1642 if (syncEnabled) {
1643 setSyncEnabled(true);
1644 }
1645
1646 // Update the storage
1647 typename MoveAction::MoveActionType moveActionType;
1648 switch (static_cast<typename FillAction::FillActionType>(fillAction.type)) {
1649
1650 case FillAction::TYPE_APPEND:
1651 moveActionType = MoveAction::TYPE_APPEND;
1652 break;
1653
1654 case FillAction::TYPE_INSERT:
1655 moveActionType = MoveAction::TYPE_INSERT;
1656 break;
1657
1658 case FillAction::TYPE_OVERWRITE:
1659 moveActionType = MoveAction::TYPE_OVERWRITE;
1660 break;
1661
1662 default:
1663 BITPIT_UNREACHABLE("This action is not handled");
1664 moveActionType = MoveAction::TYPE_UNDEFINED;
1665 break;
1666
1667 }
1668
1669 MoveAction moveAction(moveActionType);
1670 moveAction.info[PiercedSyncAction::INFO_POS_FIRST] = initialPos;
1671 moveAction.info[PiercedSyncAction::INFO_POS_SECOND] = fillAction.info[PiercedSyncAction::INFO_POS];
1672 processSyncAction(moveAction);
1673
1674 // Return the move action
1675 return moveAction;
1676}
1677
1678
1685template<typename id_t>
1686typename PiercedKernel<id_t>::SwapAction PiercedKernel<id_t>::swap(id_t id_first, id_t id_second)
1687{
1688 // Positions
1689 std::size_t pos_first = m_pos.at(id_first);
1690 std::size_t pos_second = m_pos.at(id_second);
1691
1692 // Swap the positions
1693 swapPosIds(pos_first, id_first, pos_second, id_second);
1694
1695 // Update the storage
1696 SwapAction swapAction(SwapAction::TYPE_SWAP);
1697 swapAction.info[PiercedSyncAction::INFO_POS_FIRST] = pos_first;
1698 swapAction.info[PiercedSyncAction::INFO_POS_SECOND] = pos_second;
1699 processSyncAction(swapAction);
1700
1701 // Return the swap action
1702 return swapAction;
1703}
1704
1716template<typename id_t>
1718{
1719 // Position
1720 std::size_t pos = m_pos.at(id);
1721
1722 // Pierce the position
1723 pierce(pos, flush);
1724
1725 // Update the storage
1726 if (pos + 1 < m_end_pos) {
1727 EraseAction pierceAction(EraseAction::TYPE_PIERCE);
1728 pierceAction.info[PiercedSyncAction::INFO_POS] = pos;
1729 pierceAction.info[PiercedSyncAction::INFO_POS_NEXT] = findNextUsedPos(pos);
1730 processSyncAction(pierceAction);
1731
1732 return pierceAction;
1733 } else {
1734 EraseAction resizeAction(EraseAction::TYPE_SHRINK);
1735 resizeAction.info[PiercedSyncAction::INFO_SIZE] = rawSize();
1736 processSyncAction(resizeAction);
1737
1738 return resizeAction;
1739 }
1740}
1741
1750template<typename id_t>
1752{
1753 // The kernel cannt be empty
1754 if (empty()) {
1755 throw std::out_of_range("Vector is empty");
1756 }
1757
1758 // Erase the last element
1759 std::size_t updatedRawSize;
1760 if (size() == 1) {
1761 updatedRawSize = 0;
1762 } else {
1763 updatedRawSize = findPrevUsedPos(m_end_pos - 1) + 1;
1764 }
1765
1766 rawShrink(updatedRawSize);
1767
1768 // Return the erase action
1769 EraseAction eraseAction(EraseAction::TYPE_SHRINK);
1770 eraseAction.info[PiercedSyncAction::INFO_SIZE] = rawSize();
1771 processSyncAction(eraseAction);
1772
1773 return eraseAction;
1774}
1775
1787template<typename id_t>
1788void PiercedKernel<id_t>::pierce(std::size_t pos, bool flush)
1789{
1790 // If removing the last position, there is no need to add the
1791 // position to the holes, it's enough to update the last position
1792 // counter or clear the kernel if this was the last hole.
1793 if (pos + 1 == m_end_pos) {
1794 std::size_t updatedRawSize;
1795 if (size() == 1) {
1796 updatedRawSize = 0;
1797 } else {
1798 updatedRawSize = findPrevUsedPos(m_end_pos - 1) + 1;
1799 }
1800
1801 rawShrink(updatedRawSize);
1802
1803 return;
1804 }
1805
1806 // Remove the id from the map
1807 id_t id = m_ids[pos];
1808 m_pos.erase(id);
1809
1810 // Reset the position
1811 std::size_t nextUsedPos = findNextUsedPos(pos);
1812 setPosEmptyId(pos, nextUsedPos);
1813 m_dirty_begin_pos = std::min(pos, m_dirty_begin_pos);
1814
1815 // If removing the first position, update the counter
1816 if (pos == m_begin_pos) {
1817 std::size_t begin = findNextUsedPos(m_begin_pos);
1818 setBeginPos(begin);
1819 }
1820
1821 // If the list of pending holes is full, flush the holes.
1822 if (m_holes_pending_end == m_holes.size()) {
1823 holesFlush();
1824 }
1825
1826 // Add the hole at the end of the pending holes
1827 m_holes[m_holes_pending_end] = pos;
1828 m_holes_pending_end++;
1829
1830 // Check if pending holes are still sorted
1831 if (m_holes_pending_sorted) {
1832 std::size_t nPendings = holesCountPending();
1833 if (nPendings > 1 && (m_holes[m_holes_pending_end - 1] > m_holes[m_holes_pending_end - 2])) {
1834 m_holes_pending_sorted = false;
1835 }
1836 }
1837
1838 // Flush
1839 if (flush) {
1840 holesFlush();
1841 }
1842}
1843
1850template<typename id_t>
1851void PiercedKernel<id_t>::holesClear(bool release)
1852{
1853 // Clear the holes
1854 holesResize(0, 0, 0, release);
1855
1856 // There are no holes, therefore all holes are sorted
1857 m_holes_regular_sorted = true;
1858 m_holes_pending_sorted = true;
1859}
1860
1867template<typename id_t>
1868void PiercedKernel<id_t>::holesClearRegular(bool release)
1869{
1870 // Release the memory
1871 if (release) {
1872 m_holes.shrink_to_fit();
1873 }
1874
1875 // Reset regulr holes iterators
1876 m_holes_regular_begin = 0;
1877 m_holes_regular_end = m_holes_regular_begin;
1878
1879 // There are no holes, therefore all holes are sorted
1880 m_holes_regular_sorted = true;
1881}
1882
1889template<typename id_t>
1890void PiercedKernel<id_t>::holesClearPending(bool release)
1891{
1892 // Clear section of the kernel associated with the pending holes
1893 long offset = m_holes_regular_begin;
1894 long nRegulars = holesCountRegular();
1895 holesResize(offset, nRegulars, 0, release);
1896
1897 // There are no pending holes, therefore pending holes are sorted
1898 m_holes_pending_sorted = true;
1899}
1900
1911template<typename id_t>
1912void PiercedKernel<id_t>::holesResize(std::size_t offset, std::size_t nRegulars, std::size_t nPendings, bool release)
1913{
1914 if (release) {
1915 m_holes.shrink_to_fit();
1916 }
1917
1918 m_holes.resize(offset + nRegulars + MAX_PENDING_HOLES);
1919
1920 m_holes_regular_begin = offset;
1921 m_holes_regular_end = m_holes_regular_begin + nRegulars;
1922 m_holes_pending_begin = m_holes_regular_end;
1923 m_holes_pending_end = m_holes_pending_begin + nPendings;
1924}
1925
1931template<typename id_t>
1932std::size_t PiercedKernel<id_t>::holesCount() const
1933{
1934 return holesCountPending() + holesCountRegular();
1935}
1936
1942template<typename id_t>
1943std::size_t PiercedKernel<id_t>::holesCountPending() const
1944{
1945 return (m_holes_pending_end - m_holes_pending_begin);
1946}
1947
1953template<typename id_t>
1954std::size_t PiercedKernel<id_t>::holesCountRegular() const
1955{
1956 return (m_holes_regular_end - m_holes_regular_begin);
1957}
1958
1967template<typename id_t>
1968void PiercedKernel<id_t>::holesFlush()
1969{
1970 // If there are no pending holes there is nothing to do
1971 if (m_holes_pending_begin == m_holes_pending_end) {
1972 return;
1973 }
1974
1975 // Update the id of the empty elements
1976 //
1977 // The list of pending holes is sorted, in this way we can iterate
1978 // from the last pending hole in the kernel to the first one.
1979 // We start updating the id of the last pending hole, updating also
1980 // the id of the contiguous holes before that one. Then we advance
1981 // to the next hole, skipping the positions that have already been
1982 // updated.
1983 holesSortPending();
1984
1985 std::size_t hole = m_holes_pending_begin;
1986 std::size_t pos = m_end_pos;
1987 do {
1988 if (m_holes[hole] >= pos) {
1989 hole++;
1990 continue;
1991 }
1992
1993 pos = m_holes[hole];
1994 std::size_t next_used_pos = findNextUsedPos(pos);
1995 do {
1996 setPosEmptyId(pos, next_used_pos);
1997 if (pos > 0) {
1998 pos--;
1999 } else {
2000 break;
2001 }
2002 } while (isPosEmpty(pos));
2003 } while (pos > 0 && hole != m_holes_pending_end);
2004
2005 // Move the pending holes into the list of regular holes
2006 for (std::size_t hole = m_holes_pending_begin; hole < m_holes_pending_end; ++hole) {
2007 std::size_t pos = m_holes[hole];
2008
2009 // If there is space available at the beginning of the holes, try
2010 // using pending holes to fill that gap.
2011 if (m_holes_regular_begin != 0) {
2012 --m_holes_regular_begin;
2013 m_holes[m_holes_regular_begin] = pos;
2014
2015 // Regular holes are no more sorted
2016 if (m_holes_regular_sorted) {
2017 m_holes_regular_sorted = false;
2018 }
2019 } else {
2020 if (hole != m_holes_regular_end) {
2021 m_holes[m_holes_regular_end] = pos;
2022 }
2023 ++m_holes_regular_end;
2024 ++m_holes_pending_begin;
2025
2026 // Check if regular holes are still sorted
2027 if (m_holes_regular_sorted) {
2028 std::size_t nRegulars = holesCountRegular();
2029 if (nRegulars > 1 && (m_holes[m_holes_regular_end - 1] > m_holes[m_holes_regular_end - 2])) {
2030 m_holes_regular_sorted = false;
2031 }
2032 }
2033 }
2034 }
2035
2036 // Move the holes at the beginning of the vector
2037 std::size_t nRegulars = holesCountRegular();
2038 if (nRegulars != 0 && m_holes_regular_begin != 0) {
2039 for (std::size_t k = 0; k < nRegulars; ++k) {
2040 m_holes[k] = m_holes[m_holes_regular_begin + k];
2041 }
2042
2043 m_holes_regular_begin = 0;
2044 m_holes_regular_end = m_holes_regular_begin + nRegulars;
2045 }
2046
2047 // Resize the vector
2048 holesClearPending();
2049
2050 // There are no more dirty positions
2051 m_dirty_begin_pos = m_end_pos;
2052}
2053
2054
2058template<typename id_t>
2059void PiercedKernel<id_t>::holesSortPending()
2060{
2061 if (m_holes_pending_sorted) {
2062 return;
2063 }
2064
2065 holes_iterator pending_begin_itr = m_holes.begin() + m_holes_pending_begin;
2066 holes_iterator pending_end_itr = m_holes.begin() + m_holes_pending_end;
2067 std::sort(pending_begin_itr, pending_end_itr, std::greater<std::size_t>());
2068 m_holes_pending_sorted = true;
2069}
2070
2074template<typename id_t>
2075void PiercedKernel<id_t>::holesSortRegular()
2076{
2077 if (m_holes_regular_sorted) {
2078 return;
2079 }
2080
2081 holes_iterator regular_begin_itr = m_holes.begin() + m_holes_regular_begin;
2082 holes_iterator regular_end_itr = m_holes.begin() + m_holes_regular_end;
2083 std::sort(regular_begin_itr, regular_end_itr, std::greater<std::size_t>());
2084 m_holes_regular_sorted = true;
2085}
2086
2093template<typename id_t>
2094bool PiercedKernel<id_t>::validateId(id_t id)
2095{
2096 // Ids needs to be positive
2097 if (id < 0) {
2098 throw std::out_of_range("Negative id");
2099 }
2100
2101 // Handle duplicate ids
2102 if (contains(id)) {
2103 throw std::out_of_range("Duplicate id");
2104 }
2105
2106 // Id is valid
2107 return true;
2108}
2109
2116template<typename id_t>
2117std::size_t PiercedKernel<id_t>::back() const
2118{
2119 if (empty()) {
2120 throw std::out_of_range("Vector is empty");
2121 }
2122
2123 return (m_end_pos - 1);
2124}
2125
2132template<typename id_t>
2134{
2135 if (empty()) {
2136 throw std::out_of_range("Vector is empty");
2137 }
2138
2139 return m_begin_pos;
2140}
2141
2147template<typename id_t>
2148std::vector<PiercedStorageSyncSlave<id_t> *> PiercedKernel<id_t>::getStorages()
2149{
2150 std::size_t storageIdx = 0;
2151 std::vector<PiercedStorageSyncSlave<id_t> *> storges(m_slaves.size());
2152 for (auto &slaveEntry : m_slaves) {
2153 PiercedSyncSlave *slave = slaveEntry.first;
2154 PiercedStorageSyncSlave<id_t> *piercedStorage = dynamic_cast<PiercedStorageSyncSlave<id_t> *>(slave);
2155 if (piercedStorage) {
2156 storges[storageIdx] = piercedStorage;
2157 ++storageIdx;
2158 }
2159 }
2160
2161 return storges;
2162}
2163
2169template<typename id_t>
2170std::vector<const PiercedStorageSyncSlave<id_t> *> PiercedKernel<id_t>::getStorages() const
2171{
2172 std::size_t storageIdx = 0;
2173 std::vector<PiercedStorageSyncSlave<id_t> *> storges(m_slaves.size());
2174 for (const auto &slaveEntry : m_slaves) {
2175 const PiercedSyncSlave *slave = slaveEntry.first;
2176 const PiercedStorageSyncSlave<id_t> *piercedStorage = dynamic_cast<const PiercedStorageSyncSlave<id_t> *>(slave);
2177 if (piercedStorage) {
2178 storges[storageIdx] = piercedStorage;
2179 ++storageIdx;
2180
2181 }
2182 }
2183
2184 return storges;
2185}
2186
2195template<typename id_t>
2196std::size_t PiercedKernel<id_t>::findPrevUsedPos(std::size_t pos) const
2197{
2198 std::size_t prev_pos = pos;
2199 while (true) {
2200 if (prev_pos == m_begin_pos) {
2201 throw std::out_of_range("Already in the firts position");
2202 }
2203 prev_pos--;
2204
2205 id_t prev_id = m_ids[prev_pos];
2206 if (prev_id >= 0) {
2207 return prev_pos;
2208 }
2209 }
2210}
2211
2220template<typename id_t>
2221std::size_t PiercedKernel<id_t>::findNextUsedPos(std::size_t pos) const
2222{
2223 std::size_t next_pos = pos;
2224 std::size_t next_delta = 1;
2225 while (true) {
2226 if (next_pos + 1 == m_end_pos) {
2227 throw std::out_of_range("Already in the last position");
2228 }
2229 next_pos += next_delta;
2230
2231 id_t next_id = m_ids[next_pos];
2232 if (next_id >= 0) {
2233 return next_pos;
2234 } else {
2235 next_delta = - next_id;
2236 }
2237 }
2238}
2239
2249template<typename id_t>
2250bool PiercedKernel<id_t>::isPosEmpty(std::size_t pos) const
2251{
2252 return (m_ids[pos] < 0);
2253}
2254
2261template<typename id_t>
2262void PiercedKernel<id_t>::setPosId(std::size_t pos, id_t id)
2263{
2264 m_ids[pos] = id;
2265 m_pos[id] = pos;
2266}
2267
2281template<typename id_t>
2282void PiercedKernel<id_t>::setPosEmptyId(std::size_t pos, std::size_t nextUsedPos)
2283{
2284 assert(nextUsedPos > pos);
2285
2286 // Early return if we are updating the last position
2287 //
2288 // When updating the last position, the id can only be set to point to the next position
2289 // (i.e., set equal to -1).
2290 if (pos == (m_end_pos - 1)) {
2291 m_ids[pos] = id_t(-1);
2292 return;
2293 }
2294
2295 // Set the id of the position
2296 //
2297 // The id of an empty element contains the distance, measured in number of elements, between
2298 // the current element and the next element the iterator should jump to (the distance is
2299 // negative). If the next position is non-empty or a regular hole, the value of the id will
2300 // be set in such a way to point to the next non-empty element (this will make the iterator
2301 // as fast as possible). If the next position is a pending hole, we need to set the id to
2302 // -1, otherwise we may break the iterator. For example,
2303 //
2304 // ID 1 2 3 -1 4 -1 -1 5
2305 // POS 0 1 2 3 4 5 6 7
2306 //
2307 // when setting the id associated with position 4, it should be set to -1 and not to -3,
2308 // otherwise if the position 5 will be filled, the iterator will not able to reach it (it
2309 // will reach position 4 and will wrongly skip to position 7).
2310 id_t offset = id_t(pos - nextUsedPos);
2311 if (m_ids[pos + 1] == offset + 1) {
2312 m_ids[pos] = offset;
2313 } else {
2314 m_ids[pos] = id_t(-1);
2315 }
2316}
2317
2326template<typename id_t>
2327void PiercedKernel<id_t>::swapPosIds(std::size_t pos_1, id_t id_1, std::size_t pos_2, id_t id_2)
2328{
2329 std::swap(m_ids[pos_1], m_ids[pos_2]);
2330 std::swap(m_pos[id_1], m_pos[id_2]);
2331}
2332
2336template<typename id_t>
2337void PiercedKernel<id_t>::setBeginPos(std::size_t pos)
2338{
2339 m_begin_pos = pos;
2340}
2341
2345template<typename id_t>
2346void PiercedKernel<id_t>::setEndPos(std::size_t pos)
2347{
2348 m_end_pos = pos;
2349}
2350
2356template<typename id_t>
2357void PiercedKernel<id_t>::rawShrink(std::size_t n)
2358{
2359 // We can only shrink the kernel
2360 if (n > m_end_pos) {
2361 throw std::out_of_range("The kernel can only be shrunk");
2362 }
2363
2364 // Check if we actually need to shrink the kernel
2365 if (n == m_end_pos) {
2366 return;
2367 }
2368
2369 // When the new last position is before the first one this is equivalent
2370 // to a clear
2371 if (n < (m_begin_pos + 1)) {
2372 _clear();
2373 return;
2374 }
2375
2376 // Delete the ids of the elements that will be removed
2377 for (std::size_t pos = n; pos < m_end_pos; ++pos) {
2378 id_t id = m_ids[pos];
2379 if (id >= 0) {
2380 m_pos.erase(id);
2381 }
2382 }
2383
2384 // Resize the internal vectors
2385 m_ids.resize(n);
2386
2387 // Update the last position
2388 setEndPos(n);
2389
2390 // Update the holes
2391 if (holesCount() != 0) {
2392 // Remove regular holes beyond the updated last position
2393 holesSortRegular();
2394 holes_iterator regular_begin_itr = m_holes.begin() + m_holes_regular_begin;
2395 holes_iterator regular_end_itr = m_holes.begin() + m_holes_regular_end;
2396 regular_begin_itr = std::lower_bound(regular_begin_itr, regular_end_itr, m_end_pos - 1, std::greater<std::size_t>());
2397 m_holes_regular_begin = std::distance(m_holes.begin(), regular_begin_itr);
2398 if (m_holes_regular_begin == m_holes_regular_end) {
2399 m_holes_regular_begin = 0;
2400 m_holes_regular_end = m_holes_regular_begin;
2401 }
2402
2403 // Remove pending holes beyond the updated last position
2404 holesSortPending();
2405 holes_iterator pending_begin_itr = m_holes.begin() + m_holes_pending_begin;
2406 holes_iterator pending_end_itr = m_holes.begin() + m_holes_pending_end;
2407 pending_begin_itr = std::lower_bound(pending_begin_itr, pending_end_itr, m_end_pos - 1, std::greater<std::size_t>());
2408 m_holes_pending_begin = std::distance(m_holes.begin(), pending_begin_itr);
2409 if (m_holes_pending_begin == m_holes_pending_end) {
2410 m_holes_pending_begin = m_holes_regular_end;
2411 m_holes_pending_end = m_holes_pending_begin;
2412 }
2413 }
2414}
2415
2421template<typename id_t>
2422void PiercedKernel<id_t>::restore(std::istream &stream)
2423{
2424 // Ids data
2425 std::size_t nIds;
2426 utils::binary::read(stream, nIds);
2427 m_pos.reserve(nIds);
2428 for (std::size_t n = 0; n < nIds; ++n) {
2429 id_t id;
2430 utils::binary::read(stream, id);
2431
2432 std::size_t pos;
2433 utils::binary::read(stream, pos);
2434
2435 m_pos.insert({id, pos});
2436 }
2437
2438 // Postions data
2439 std::size_t nPositions;
2440 utils::binary::read(stream, nPositions);
2441 m_ids.resize(nPositions);
2442 for (std::size_t n = 0; n < nPositions; ++n) {
2443 std::size_t id;
2444 utils::binary::read(stream, id);
2445
2446 m_ids[n] = id;
2447 }
2448
2449 utils::binary::read(stream, m_begin_pos);
2450 utils::binary::read(stream, m_end_pos);
2451 utils::binary::read(stream, m_dirty_begin_pos);
2452
2453 // Holes data
2454 std::size_t nHoles;
2455 utils::binary::read(stream, nHoles);
2456 m_holes.resize(nHoles);
2457 for (std::size_t n = 0; n < nHoles; ++n) {
2458 std::size_t pos;
2459 utils::binary::read(stream, pos);
2460
2461 m_holes[n] = pos;
2462 }
2463
2464 utils::binary::read(stream, m_holes_regular_begin);
2465 utils::binary::read(stream, m_holes_regular_end);
2466 utils::binary::read(stream, m_holes_pending_begin);
2467 utils::binary::read(stream, m_holes_pending_end);
2468 utils::binary::read(stream, m_holes_regular_sorted);
2469 utils::binary::read(stream, m_holes_pending_sorted);
2470
2471 // Synchronization data
2473}
2474
2480template<typename id_t>
2481void PiercedKernel<id_t>::dump(std::ostream &stream) const
2482{
2483 // Ids data
2484 std::size_t nIds = m_pos.size();
2485 utils::binary::write(stream, nIds);
2486 for (const auto &entry : m_pos) {
2487 utils::binary::write(stream, entry.first);
2488 utils::binary::write(stream, entry.second);
2489 }
2490
2491 // Postions data
2492 std::size_t nPositions = m_ids.size();
2493 utils::binary::write(stream, nPositions);
2494 for (std::size_t pos : m_ids) {
2495 utils::binary::write(stream, pos);
2496 }
2497
2498 utils::binary::write(stream, m_begin_pos);
2499 utils::binary::write(stream, m_end_pos);
2500 utils::binary::write(stream, m_dirty_begin_pos);
2501
2502 // Holes data
2503 std::size_t nHoles = m_holes.size();
2504 utils::binary::write(stream, nHoles);
2505 for (std::size_t hole : m_holes) {
2506 utils::binary::write(stream, hole);
2507 }
2508
2509 utils::binary::write(stream, m_holes_regular_begin);
2510 utils::binary::write(stream, m_holes_regular_end);
2511 utils::binary::write(stream, m_holes_pending_begin);
2512 utils::binary::write(stream, m_holes_pending_end);
2513 utils::binary::write(stream, m_holes_regular_sorted);
2514 utils::binary::write(stream, m_holes_pending_sorted);
2515
2516 // Synchronization data
2518}
2519
2520}
2521
2522#endif
Base class for the pierced kernel.
Iterator for the class PiercedKernel.
Metafunction for generating a pierced kernel.
ResizeAction resize(std::size_t n)
std::size_t getPos(id_t id) const
const_iterator rawFind(std::size_t pos) const noexcept
FillAction fillHole(std::size_t hole, id_t id)
bool isPosEmpty(std::size_t pos) const
std::vector< id_t > getIds(bool ordered=true) const
SqueezeAction _squeeze()
std::size_t rawSize() const
std::size_t findNextUsedPos(std::size_t pos) const
std::size_t findPrevUsedPos(std::size_t pos) const
SortAction sortBefore(id_t referenceId, bool inclusive)
ResizeAction _resize(std::size_t n)
void updateId(const id_t &currentId, const id_t &updatedId)
const_iterator cend() const noexcept
EraseAction erase(id_t id, bool flush=false)
const_iterator find(const id_t &id) const noexcept
FillAction fillAppend(id_t id)
SqueezeAction squeeze()
bool contains(id_t id) const
ClearAction _clear(bool release=true)
std::size_t getRawIndex(id_t id) const
const_iterator begin() const noexcept
MoveAction moveAfter(id_t referenceId, id_t id, bool flush=false)
ClearAction clear(bool release=true)
ReserveAction reserve(std::size_t n)
std::size_t getFirstUsedPos() const
SortAction _sort(std::size_t begin, std::size_t end)
id_t getSizeMarker(std::size_t targetSize, const id_t &fallback=-1)
FillAction fillAfter(id_t referenceId, id_t id)
FillAction fillBefore(id_t referenceId, id_t id)
FillAction fillInsert(std::size_t pos, id_t id)
std::size_t count(id_t id) const
std::size_t front() const
ShrinkToFitAction _shrinkToFit()
const_iterator cbegin() const noexcept
void swap(PiercedKernel &other) noexcept
holes_container::const_iterator holes_const_iterator
std::size_t evalFlatIndex(id_t id) const
FillAction fillHead(id_t id)
std::size_t maxSize() const
void restore(std::istream &stream)
SortAction sortAfter(id_t referenceId, bool inclusive)
const_iterator end() const noexcept
ShrinkToFitAction shrinkToFit()
std::size_t capacity() const
std::size_t getLastUsedPos() const
FillAction fillTail(id_t id)
std::size_t size() const
MoveAction moveBefore(id_t referenceId, id_t id, bool flush=false)
ReserveAction _reserve(std::size_t n)
std::vector< PiercedStorageSyncSlave< id_t > * > getStorages()
std::size_t back() const
holes_container::iterator holes_iterator
Base class for defining storages that acts like a slave in pierced synchronization.
void swap(PiercedSyncAction &other) noexcept
void importData(std::vector< std::size_t > &&values)
void restore(std::istream &stream)
void swap(PiercedSyncMaster &other) noexcept
void dump(std::ostream &stream) const
Base class for defining an object that acts like a slave in pierced synchronization.
void write(std::ostream &stream, const std::vector< bool > &container)
void read(std::istream &stream, std::vector< bool > &container)
#define BITPIT_UNREACHABLE(str)
Definition compiler.hpp:53
--- layout: doxygen_footer ---