4#include "Stroika/Frameworks/StroikaPreComp.h"
6#include "ChunkedArrayTextStore.h"
9using namespace Stroika::Foundation::Memory;
11using namespace Stroika::Frameworks;
12using namespace Stroika::Frameworks::Led;
17#if qStroika_Foundation_Debug_AssertionsChecked
21class ChunkedArrayTextStore::TextChunk {
23 TextChunk () =
default;
24 TextChunk (
const Led_tChar* copyFrom,
size_t bytesToCopy);
28 kTextChunkSize = (4096 -
sizeof (size_t) - 8) /
sizeof (Led_tChar)
37 nonvirtual
size_t GetLength () const noexcept;
38 nonvirtual
size_t GetBytesCanAccommodate () const noexcept;
39 nonvirtual
void CopyOut (
size_t from,
size_t count, Led_tChar* buffer) const noexcept;
40 nonvirtual const Led_tChar* PeekAfter (
size_t charPos) const noexcept;
41 nonvirtual
void InsertAfter (const Led_tChar* what,
size_t howMany,
size_t after) noexcept;
42 nonvirtual
void DeleteAfter (
size_t howMany,
size_t after) noexcept;
45 size_t fTotalTcharsUsed{0};
46 Led_tChar fData[kTextChunkSize];
50inline ChunkedArrayTextStore::TextChunk::TextChunk (
const Led_tChar* copyFrom,
size_t bytesToCopy)
51 : fTotalTcharsUsed{bytesToCopy}
53 Assert (bytesToCopy <= kTextChunkSize);
55 (void)::memcpy (fData, copyFrom, bytesToCopy *
sizeof (Led_tChar));
57inline size_t ChunkedArrayTextStore::TextChunk::GetLength () const noexcept
59 return (fTotalTcharsUsed);
61inline size_t ChunkedArrayTextStore::TextChunk::GetBytesCanAccommodate () const noexcept
63 return (kTextChunkSize - fTotalTcharsUsed);
65inline void ChunkedArrayTextStore::TextChunk::CopyOut (
size_t from,
size_t count, Led_tChar* buffer)
const noexcept
68 Assert (from + count <= fTotalTcharsUsed);
69 (void)::memcpy (buffer, &fData[from], count *
sizeof (Led_tChar));
71inline const Led_tChar* ChunkedArrayTextStore::TextChunk::PeekAfter (
size_t charPos)
const noexcept
73 Assert (charPos >= 0);
74 Assert (charPos < fTotalTcharsUsed);
75 return (&fData[charPos]);
77inline void ChunkedArrayTextStore::TextChunk::InsertAfter (
const Led_tChar* what,
size_t howMany,
size_t after)
noexcept
79 Assert (what != 0 or howMany == 0);
81 Assert (after <= fTotalTcharsUsed);
82 Assert (after + howMany <= kTextChunkSize);
87 Assert (fTotalTcharsUsed >= after);
88 size_t bytesToMove = fTotalTcharsUsed - after;
89 if (bytesToMove != 0) {
90 (void)memmove (&fData[after + howMany], &fData[after], bytesToMove *
sizeof (Led_tChar));
92 (void)::memcpy (&fData[after], what, howMany *
sizeof (Led_tChar));
93 fTotalTcharsUsed += howMany;
95inline void ChunkedArrayTextStore::TextChunk::DeleteAfter (
size_t howMany,
size_t after)
noexcept
97 Require (after + howMany <= fTotalTcharsUsed);
98 size_t bytesToMove = fTotalTcharsUsed - (after + howMany);
99 if (bytesToMove != 0) {
100 (void)::memmove (&fData[after], &fData[after + howMany], bytesToMove *
sizeof (Led_tChar));
102 fTotalTcharsUsed -= howMany;
113const size_t kEnufChildrenToApplyHackMarkers = 50;
118 ChunkedArrayMarkerHook () =
default;
122 virtual size_t GetStart ()
const override;
123 virtual size_t GetEnd ()
const override;
124 virtual size_t GetLength ()
const override;
125 virtual void GetStartEnd (
size_t* start,
size_t* end)
const override;
127 nonvirtual
void AddToChildList (Marker* marker);
128 nonvirtual
size_t CountChildren ()
const;
129 nonvirtual
bool CountChildrenMoreThan (
size_t n)
const;
134 Marker* fFirstSubMarker;
135 Marker* fNextSubMarker;
137 Marker* fParent{
nullptr};
138 bool fIsHackMarker : 1 {
false};
139 bool fIsDeletedMarker : 1 {
false};
140 bool fIsPreRemoved : 1 {
false};
149 HackMarker () =
default;
152MarkerOwner* ChunkedArrayMarkerHook::GetOwner ()
const
159size_t ChunkedArrayMarkerHook::GetStart ()
const
161 Assert (fStart < 0x8000000);
167size_t ChunkedArrayMarkerHook::GetEnd ()
const
169 Assert (fStart < 0x8000000);
170 Assert (fLength < 0x8000000);
171 return fStart + fLength;
174size_t ChunkedArrayMarkerHook::GetLength ()
const
176 Assert (fLength < 0x8000000);
180void ChunkedArrayMarkerHook::GetStartEnd (
size_t* start,
size_t* end)
const
182 Assert (fStart < 0x8000000);
183 Assert (fLength < 0x8000000);
187 *end = fStart + fLength;
195static inline ChunkedArrayMarkerHook* OurStuff (
const Marker* marker)
199 AssertMember (marker->fTextStoreHook, ChunkedArrayMarkerHook);
201 return (ChunkedArrayMarkerHook*)marker->fTextStoreHook;
204inline void ChunkedArrayMarkerHook::AddToChildList (Marker* marker)
207 OurStuff (marker)->fNextSubMarker = fFirstSubMarker;
208 fFirstSubMarker = marker;
210inline size_t ChunkedArrayMarkerHook::CountChildren ()
const
212 size_t nChildren = 0;
213 for (
auto curChild = fFirstSubMarker; curChild != NULL; curChild = OurStuff (curChild)->fNextSubMarker) {
218inline bool ChunkedArrayMarkerHook::CountChildrenMoreThan (
size_t n)
const
220 size_t nChildren = 0;
221 for (
auto curChild = fFirstSubMarker; curChild != NULL; curChild = OurStuff (curChild)->fNextSubMarker) {
223 if (nChildren >= n) {
227 return nChildren >= n;
229inline bool ChunkedArrayTextStore::AllHackMarkers (
const Marker* m)
232 return (OurStuff (m)->fIsHackMarker and (OurStuff (m)->fFirstSubMarker == NULL or AllSubMarkersAreHackMarkerTrees (m)));
234inline ChunkedArrayTextStore::TextChunk* ChunkedArrayTextStore::AtomicAddChunk (
size_t atArrayPos)
236 TextChunk* t =
new TextChunk ();
240 fTextChunks.insert (fTextChunks.begin () + atArrayPos, t);
250static inline size_t GetMarkerStart_ (Marker* m)
253 Ensure (OurStuff (m)->fStart == m->GetStart ());
254 return OurStuff (m)->fStart;
256static inline void SetMarkerStart_ (Marker* m,
size_t s)
258 OurStuff (m)->fStart = s;
260static inline size_t GetMarkerLength_ (Marker* m)
263 Ensure (OurStuff (m)->fLength == m->GetLength ());
264 return OurStuff (m)->fLength;
266static inline void SetMarkerLength_ (Marker* m,
size_t s)
268 OurStuff (m)->fLength = s;
270static inline void SetMarkerOwner_ (Marker* m,
MarkerOwner* o)
272 OurStuff (m)->fOwner = o;
275static inline bool QUICK_Overlap (ChunkedArrayMarkerHook* h,
size_t from,
size_t to)
281 size_t start = h->fStart;
285 size_t end = start + h->fLength;
287 if ((from <= end) and (start <= to)) {
291 size_t a = end - from;
292 size_t b = end - start;
293 overlapSize = min (a, b);
296 size_t a = to - from;
297 size_t b = to - start;
298 overlapSize = min (a, b);
300 if (overlapSize == 0) {
311static inline bool QUICK_Overlap (
const Marker& m,
size_t from,
size_t to)
313 bool result = QUICK_Overlap (OurStuff (&m), from, to);
314 Assert (result == TextStore::Overlap (m, from, to));
317static inline bool QUICK_Contains (
size_t containedStart,
size_t containedEnd,
size_t containerStart,
size_t containerEnd)
319 return (containedStart >= containerStart) and (containerEnd >= containedEnd);
321static inline bool QUICK_Contains (
const Marker& containedMarker,
const Marker& containerMarker)
323 ChunkedArrayMarkerHook* h = OurStuff (&containerMarker);
324 size_t containerStart = h->fStart;
325 size_t containerEnd = containerStart + h->fLength;
327 ChunkedArrayMarkerHook* h1 = OurStuff (&containedMarker);
328 size_t containedStart = h1->fStart;
329 size_t containedEnd = containedStart + h1->fLength;
331 bool result = QUICK_Contains (containedStart, containedEnd, containerStart, containerEnd);
332 Assert (result == Contains (containedMarker, containerMarker));
336#if qUseLRUCacheForRecentlyLookedUpMarkers
337struct ChunkedArrayTextStore::CollectLookupCacheElt {
338 vector<Marker*> fMarkers;
342 struct COMPARE_ITEM {
343 COMPARE_ITEM (
size_t from,
size_t to)
353 nonvirtual
void Clear ()
355 fFrom =
static_cast<size_t> (-1);
357 static bool Equal (
const CollectLookupCacheElt& lhs,
const COMPARE_ITEM& rhs)
359 return lhs.fFrom == rhs.fFrom and lhs.fTo == rhs.fTo;
364class ChunkedArrayMarkerOwnerHook :
public MarkerOwner::HookData {
366 using inherited = MarkerOwner::HookData;
369 ChunkedArrayMarkerOwnerHook (
MarkerOwner* mo,
size_t len)
371#if qUseLRUCacheForRecentlyLookedUpMarkers
376#if qKeepChunkedArrayStatistics
377 , fTotalMarkersPresent{0}
378 , fTotalHackMarkersPresent{0}
379 , fPeakTotalMarkersPresent{0}
380 , fPeakHackMarkersPresent{0}
381 , fTotalHackMarkersAlloced{0}
384 Assert (fRootMarker.fTextStoreHook == NULL);
385 fRootMarker.fTextStoreHook =
new ChunkedArrayMarkerHook ();
386 SetMarkerOwner_ (&fRootMarker, mo);
387 SetMarkerStart_ (&fRootMarker, 0);
388 SetMarkerLength_ (&fRootMarker, len);
390 ~ChunkedArrayMarkerOwnerHook ()
392#if qKeepChunkedArrayStatistics
393 Require (fTotalMarkersPresent == 0);
416 for (Marker* mi = OurStuff (&fRootMarker)->fFirstSubMarker; mi != NULL; mi = OurStuff (&fRootMarker)->fFirstSubMarker) {
417 Assert (AllHackMarkers (mi));
423#if qKeepChunkedArrayStatistics
424 Assert (fTotalHackMarkersPresent == 0);
428 Assert (OurStuff (&fRootMarker)->fFirstSubMarker == NULL);
430 if (fRootMarker.fTextStoreHook != NULL) {
431 SetMarkerOwner_ (&fRootMarker, NULL);
433 delete ((ChunkedArrayMarkerHook*)fRootMarker.fTextStoreHook);
436#if qUseLRUCacheForRecentlyLookedUpMarkers
438 using CollectLookupCacheElt = ChunkedArrayTextStore::CollectLookupCacheElt;
443 nonvirtual
void ClearCache ()
445 fCache.ClearCache ();
447 nonvirtual CollectLookupCacheElt* LookupElement (
const CollectLookupCacheElt::COMPARE_ITEM& item)
449 return fCache.LookupElement (item);
451 nonvirtual CollectLookupCacheElt* AddNew (
const CollectLookupCacheElt::COMPARE_ITEM& item)
453 return fCache.AddNew (item);
461 inline bool AllHackMarkers (
const Marker* m)
464 return (OurStuff (m)->fIsHackMarker and (OurStuff (m)->fFirstSubMarker == NULL or AllSubMarkersAreHackMarkerTrees (m)));
468 nonvirtual
bool AllSubMarkersAreHackMarkerTrees (
const Marker* m)
471 Assert (OurStuff (m)->fIsHackMarker);
474 size_t stackDepth = 0;
482 for (
auto mi = OurStuff (m)->fFirstSubMarker; mi != NULL;) {
483 ChunkedArrayMarkerHook* misStuff = OurStuff (mi);
484 Assert (misStuff->fParent == m);
485 if (not misStuff->fIsHackMarker) {
488 mi = misStuff->fNextSubMarker;
491 auto mi = OurStuff (m)->fFirstSubMarker;
492 for (; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
493 Assert (OurStuff (mi)->fIsHackMarker);
495 stack.GrowToSize (stackDepth + 1);
496 stack[stackDepth] = mi;
501 Assert (stackDepth > 0);
503 mi = stack[stackDepth];
506 if (stackDepth != 0) {
514 nonvirtual
void FreeHackTree (Marker* m)
517 Assert (OurStuff (m)->fIsHackMarker);
520 Marker* parent = OurStuff (m)->fParent;
522 Marker* prevMarker = NULL;
523 for (
auto mi = OurStuff (parent)->fFirstSubMarker; mi != NULL; (prevMarker = mi), (mi = OurStuff (mi)->fNextSubMarker)) {
524 Assert (OurStuff (mi)->fParent == parent);
526 if (prevMarker == NULL) {
527 Assert (OurStuff (parent)->fFirstSubMarker == mi);
528 OurStuff (parent)->fFirstSubMarker = OurStuff (mi)->fNextSubMarker;
531 Assert (OurStuff (prevMarker)->fNextSubMarker == mi);
532 OurStuff (prevMarker)->fNextSubMarker = OurStuff (mi)->fNextSubMarker;
534 OurStuff (mi)->fNextSubMarker = NULL;
542 nonvirtual
void FreeHackTree1 (Marker* m)
545 Assert (OurStuff (m)->fIsHackMarker);
547 for (Marker* mi = OurStuff (m)->fFirstSubMarker; mi != NULL;) {
548 Marker* nextMI = OurStuff (mi)->fNextSubMarker;
553 bool isDeletedMarker = OurStuff (m)->fIsDeletedMarker;
554 delete ((ChunkedArrayMarkerHook*)m->fTextStoreHook);
556 if (isDeletedMarker) {
557 m->fTextStoreHook = NULL;
561 m->fTextStoreHook = (ChunkedArrayMarkerHook*)666;
564#if qKeepChunkedArrayStatistics
565 Assert (fTotalHackMarkersPresent > 0);
566 --fTotalHackMarkersPresent;
574#if qKeepChunkedArrayStatistics
576 unsigned long fTotalMarkersPresent;
577 unsigned long fTotalHackMarkersPresent;
578 unsigned long fPeakTotalMarkersPresent;
579 unsigned long fPeakHackMarkersPresent;
580 unsigned long fTotalHackMarkersAlloced;
584inline ChunkedArrayMarkerOwnerHook* GetAMOH (
const MarkerOwner* mo)
588 RequireNotNull (
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (mo->fTextStoreHook));
589 return dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (mo->fTextStoreHook);
591inline ChunkedArrayMarkerOwnerHook* GetAMOH (ChunkedArrayMarkerHook* moh)
594 return GetAMOH (moh->fOwner);
596inline ChunkedArrayMarkerOwnerHook* GetAMOH (Marker* m)
598 return GetAMOH (OurStuff (m));
618ChunkedArrayTextStore::ChunkedArrayTextStore ()
620 fTextStoreHook =
new ChunkedArrayMarkerOwnerHook (
this, 2);
623ChunkedArrayTextStore::~ChunkedArrayTextStore ()
625 Require (GetMarkerOwners ().size () == 1);
634 delete fTextStoreHook;
635 fTextStoreHook = NULL;
638 for (
size_t i = 0; i < fTextChunks.size (); i++) {
639 delete fTextChunks[i];
647TextStore* ChunkedArrayTextStore::ConstructNewTextStore ()
const
649 return new ChunkedArrayTextStore ();
652void ChunkedArrayTextStore::AddMarkerOwner (
MarkerOwner* owner)
655 Require (owner->fTextStoreHook == NULL);
656 inherited::AddMarkerOwner (owner);
658 owner->fTextStoreHook =
new ChunkedArrayMarkerOwnerHook (owner, GetLength () + 2);
665 inherited::RemoveMarkerOwner (owner);
670void ChunkedArrayTextStore::RemoveMarkerOwner (
MarkerOwner* owner)
674 RequireNotNull (
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook));
675#if qKeepChunkedArrayStatistics
677 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook);
678 Require (camoh->fTotalMarkersPresent == 0);
687 if (camoh->fTotalMarkersPresent != 0) {
688 vector<Marker*> markersWhichShouldHaveBeenDeleted;
689 VectorMarkerSink tmp{&markersWhichShouldHaveBeenDeleted};
690 CollectAllMarkersInRangeInto (0, GetEnd () + 2, owner, tmp);
695 delete owner->fTextStoreHook;
696 owner->fTextStoreHook = NULL;
697 inherited::RemoveMarkerOwner (owner);
700void ChunkedArrayTextStore::CopyOut (
size_t from,
size_t count, Led_tChar* buffer)
const noexcept
706 Require (from + count <= GetEnd ());
708 ChunkAndOffset chunkIdx = FindChunkIndex (from);
709 for (
size_t bytesToGo = count; bytesToGo != 0;) {
710 Assert (chunkIdx.fChunk >= 0);
711 Assert (chunkIdx.fChunk < fTextChunks.size ());
713 TextChunk* t = fTextChunks[chunkIdx.fChunk];
715 size_t copyFromThisGuy = min (bytesToGo, t->GetLength () - (chunkIdx.fOffset));
716 t->CopyOut (chunkIdx.fOffset, copyFromThisGuy, &buffer[count - bytesToGo]);
719 chunkIdx.fOffset = 0;
721 bytesToGo -= copyFromThisGuy;
725void ChunkedArrayTextStore::ReplaceWithoutUpdate (
size_t from,
size_t to,
const Led_tChar* withWhat,
size_t withWhatCount)
727#if qUseLRUCacheForRecentlyLookedUpMarkers
728 for (vector<MarkerOwner*>::const_iterator i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
729 GetAMOH (*i)->ClearCache ();
733 if (from != to or withWhatCount != 0) {
764 DeleteAfter_ (to - from, from);
766 if (withWhatCount != 0) {
767 InsertAfter_ (withWhat, withWhatCount, from);
772void ChunkedArrayTextStore::InsertAfter_ (
const Led_tChar* what,
size_t howMany,
size_t after)
774 Assert (howMany > 0);
775 Assert (what != NULL);
777 Assert (howMany > 0);
778 Assert (what != NULL);
780 ChunkAndOffset chunkIdx = FindChunkIndex (after);
787 if (chunkIdx.fChunk >= fTextChunks.size ()) {
788 if (fTextChunks.size () == 0) {
789 (void)AtomicAddChunk (0);
795 Assert (chunkIdx.fChunk >= 1);
796 TextChunk* preChunk = fTextChunks[chunkIdx.fChunk - 1];
797 if (preChunk->GetBytesCanAccommodate () == 0) {
798 (void)AtomicAddChunk (fTextChunks.size ());
802 chunkIdx.fOffset = preChunk->GetLength ();
806 TextChunk* t = fTextChunks[chunkIdx.fChunk];
813 size_t bytesXfered = 0;
815 if (t->GetBytesCanAccommodate () >= howMany) {
819 t->InsertAfter (what, howMany, chunkIdx.fOffset);
820 bytesXfered += howMany;
833 if (chunkIdx.fChunk == fTextChunks.size () - 1) {
834 (void)AtomicAddChunk (chunkIdx.fChunk + 1);
836 TextChunk* followingChunk = fTextChunks[chunkIdx.fChunk + 1];
838 size_t splitPoint = chunkIdx.fOffset;
839 size_t bytesToShift = t->GetLength () - (splitPoint);
840 const Led_tChar* peekAfter = (bytesToShift == 0) ? NULL : t->PeekAfter (splitPoint);
841 if (followingChunk->GetBytesCanAccommodate () >= bytesToShift) {
842 followingChunk->InsertAfter (peekAfter, bytesToShift, 0);
849 followingChunk = AtomicAddChunk (chunkIdx.fChunk + 1);
850 followingChunk->InsertAfter (peekAfter, bytesToShift, 0);
852 t->DeleteAfter (bytesToShift, splitPoint);
861 size_t bytesToGo = howMany;
862 size_t copyFromThisGuy = min (bytesToGo, t->GetBytesCanAccommodate ());
863 t->InsertAfter (&what[bytesXfered], copyFromThisGuy, chunkIdx.fOffset);
865 bytesToGo -= copyFromThisGuy;
866 bytesXfered += copyFromThisGuy;
868 for (; bytesToGo != 0;) {
870 if (chunkIdx.fChunk <= fTextChunks.size () - 1 and fTextChunks[chunkIdx.fChunk]->GetBytesCanAccommodate () >= bytesToGo) {
872 t = fTextChunks[chunkIdx.fChunk];
873 t->InsertAfter (&what[bytesXfered], bytesToGo, 0);
874 bytesXfered += bytesToGo;
875 bytesToGo -= bytesToGo;
876 Assert (bytesToGo == 0);
877 Assert (bytesXfered == howMany);
882 t = AtomicAddChunk (chunkIdx.fChunk);
884 copyFromThisGuy = min (bytesToGo, t->GetBytesCanAccommodate ());
885 t->InsertAfter (&what[bytesXfered], copyFromThisGuy, 0);
886 bytesToGo -= copyFromThisGuy;
887 bytesXfered += copyFromThisGuy;
893 fLength += bytesXfered;
894 AdjustMarkersForInsertAfter (after, bytesXfered);
898 Assert (howMany == bytesXfered);
899 fLength += bytesXfered;
900 AdjustMarkersForInsertAfter (after, bytesXfered);
903void ChunkedArrayTextStore::DeleteAfter_ (
size_t howMany,
size_t after)
906 Assert ((after) + howMany <= GetLength ());
907 Assert (howMany > 0);
909 ChunkAndOffset chunkIdx = FindChunkIndex (after);
910 for (
size_t bytesToGo = howMany; bytesToGo != 0;) {
912 TextChunk* t = fTextChunks[chunkIdx.fChunk];
916 size_t deleteFromThisGuy = min (bytesToGo, t->GetLength () - (chunkIdx.fOffset));
917 Assert (deleteFromThisGuy != 0);
918 t->DeleteAfter (deleteFromThisGuy, chunkIdx.fOffset);
919 bytesToGo -= deleteFromThisGuy;
920 fLength -= deleteFromThisGuy;
923 chunkIdx.fOffset = 0;
924 chunkIdx.fChunk += 1;
930 if (t->GetLength () == 0) {
931 chunkIdx.fChunk -= 1;
932 fTextChunks.erase (fTextChunks.begin () + chunkIdx.fChunk);
936 AdjustMarkersForDeleteAfter (after, howMany);
939void ChunkedArrayTextStore::AddMarker (Marker* marker,
size_t lhs,
size_t length,
MarkerOwner* owner)
943#if !qVirtualBaseMixinCallDuringCTORBug
944 Require (owner->PeekAtTextStore () ==
this);
946 Require (owner ==
this or IndexOf (GetMarkerOwners (), owner) != kBadIndex);
947 Require (marker->fTextStoreHook == NULL);
948 Require (lhs < 0x80000000);
949 Require (length < 0x80000000);
950 Require (lhs + length <= fLength + 1);
953 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook);
956#if qUseLRUCacheForRecentlyLookedUpMarkers
957 camoh->ClearCache ();
960 marker->fTextStoreHook =
new ChunkedArrayMarkerHook ();
963 SetMarkerOwner_ (marker, owner);
965 SetMarkerStart_ (marker, lhs);
966 SetMarkerLength_ (marker, length);
968 AddMarker1 (marker, &camoh->fRootMarker,
true);
970#if qKeepChunkedArrayStatistics
971 ++camoh->fTotalMarkersPresent;
972 camoh->fPeakTotalMarkersPresent = max (camoh->fPeakTotalMarkersPresent, camoh->fTotalMarkersPresent);
977#ifndef qKeepTrackOfChildCountAndAvoidSomePossiblyAdds
978#define qKeepTrackOfChildCountAndAvoidSomePossiblyAdds 1
981void ChunkedArrayTextStore::AddMarker1 (Marker* marker, Marker* insideMarker,
bool canAddHackMarkers)
985 Assert (marker != insideMarker);
988 Assert (QUICK_Contains (*marker, *insideMarker));
989 Assert (OurStuff (marker)->fParent == NULL);
990 Assert (OurStuff (marker)->fNextSubMarker == NULL);
993 size_t markerStart = GetMarkerStart_ (marker);
994 size_t markerEnd = markerStart + GetMarkerLength_ (marker);
1008 Marker* specificInsideMarker = insideMarker;
1010#if qKeepTrackOfChildCountAndAvoidSomePossiblyAdds
1011 size_t specificInsideMarkerChildCount = 0;
1013 Marker* prevMarker = NULL;
1014 for (Marker* curChild = OurStuff (specificInsideMarker)->fFirstSubMarker; curChild != NULL;
1015 (prevMarker = curChild), (curChild = OurStuff (curChild)->fNextSubMarker)) {
1016 Assert (marker != curChild);
1018#if qKeepTrackOfChildCountAndAvoidSomePossiblyAdds
1019 ++specificInsideMarkerChildCount;
1034 size_t curChildStart = GetMarkerStart_ (curChild);
1035 size_t curChildEnd = curChildStart + GetMarkerLength_ (curChild);
1036 if (markerStart == curChildStart and markerEnd == curChildEnd and OurStuff (marker)->fFirstSubMarker == NULL) {
1037 Assert (QUICK_Contains (*marker, *curChild));
1042 Assert (OurStuff (marker)->fParent == NULL);
1043 OurStuff (marker)->fParent = OurStuff (curChild)->fParent;
1045 Assert (OurStuff (marker)->fFirstSubMarker == NULL);
1046 OurStuff (marker)->fFirstSubMarker = OurStuff (curChild)->fFirstSubMarker;
1048 Assert (OurStuff (marker)->fNextSubMarker == NULL);
1049 OurStuff (marker)->fNextSubMarker = OurStuff (curChild)->fNextSubMarker;
1052 if (prevMarker == NULL) {
1053 Assert (OurStuff (marker)->fParent == specificInsideMarker);
1054 Assert (OurStuff (specificInsideMarker)->fFirstSubMarker == curChild);
1055 OurStuff (specificInsideMarker)->fFirstSubMarker = marker;
1058 Assert (OurStuff (prevMarker)->fNextSubMarker == curChild);
1059 OurStuff (prevMarker)->fNextSubMarker = marker;
1063 OurStuff (curChild)->fNextSubMarker = OurStuff (marker)->fFirstSubMarker;
1064 OurStuff (marker)->fFirstSubMarker = curChild;
1065 OurStuff (curChild)->fFirstSubMarker = NULL;
1066 OurStuff (curChild)->fParent = marker;
1070 for (Marker* mm = OurStuff (marker)->fFirstSubMarker; mm != NULL; mm = OurStuff (mm)->fNextSubMarker) {
1071 Assert (OurStuff (mm)->fParent == curChild or (mm == curChild));
1072 OurStuff (mm)->fParent = marker;
1078 Assert (QUICK_Contains (*marker, *curChild) == QUICK_Contains (markerStart, markerEnd, curChildStart, curChildEnd));
1079 if (QUICK_Contains (markerStart, markerEnd, curChildStart, curChildEnd)) {
1080 specificInsideMarker = curChild;
1085#if qKeepTrackOfChildCountAndAvoidSomePossiblyAdds
1086 if (specificInsideMarkerChildCount < kEnufChildrenToApplyHackMarkers) {
1087 canAddHackMarkers =
false;
1096 OurStuff (specificInsideMarker)->AddToChildList (marker);
1097 Assert (OurStuff (marker)->fParent == NULL);
1098 OurStuff (marker)->fParent = specificInsideMarker;
1101 if (canAddHackMarkers) {
1102 PossiblyAddHackMarkers (specificInsideMarker);
1106void ChunkedArrayTextStore::PossiblyAddHackMarkers (Marker* insideMarker)
1112 if (GetMarkerLength_ (insideMarker) >= 2 and OurStuff (insideMarker)->CountChildrenMoreThan (kEnufChildrenToApplyHackMarkers)) {
1113 size_t insideMarkerStart = GetMarkerStart_ (insideMarker);
1114 size_t insideMarkerEnd = insideMarkerStart + GetMarkerLength_ (insideMarker);
1115 size_t insideMarkerLength = insideMarkerEnd - insideMarkerStart;
1124 lhs = AddHackMarkerHelper_ (insideMarker, insideMarkerStart, insideMarkerLength / 2);
1125 size_t rhsStart = insideMarkerStart + insideMarkerLength / 2;
1126 rhs = AddHackMarkerHelper_ (insideMarker, rhsStart, insideMarkerEnd - rhsStart);
1130 Assert (OurStuff (insideMarker)->CountChildren () > 2);
1131 Marker* prevMarker = NULL;
1132 for (Marker* curMarker = OurStuff (insideMarker)->fFirstSubMarker; curMarker != NULL;) {
1133 Marker* nextMarker = OurStuff (curMarker)->fNextSubMarker;
1134 if (curMarker != lhs and curMarker != rhs) {
1135 DISABLE_COMPILER_MSC_WARNING_START (6011)
1136 if (QUICK_Contains (*curMarker, *lhs)) {
1139 OurStuff (prevMarker)->fNextSubMarker = OurStuff (curMarker)->fNextSubMarker;
1140 OurStuff (curMarker)->fNextSubMarker = NULL;
1141 Assert (OurStuff (curMarker)->fParent == insideMarker);
1142 OurStuff (curMarker)->fParent = NULL;
1143 AddMarker1 (curMarker, lhs,
false);
1145 curMarker = nextMarker;
1148 else if (QUICK_Contains (*curMarker, *rhs)) {
1151 OurStuff (prevMarker)->fNextSubMarker = OurStuff (curMarker)->fNextSubMarker;
1152 OurStuff (curMarker)->fNextSubMarker = NULL;
1153 Assert (OurStuff (curMarker)->fParent == insideMarker);
1154 OurStuff (curMarker)->fParent = NULL;
1155 AddMarker1 (curMarker, rhs,
false);
1157 curMarker = nextMarker;
1160 DISABLE_COMPILER_MSC_WARNING_END (6011)
1162 prevMarker = curMarker;
1163 curMarker = nextMarker;
1165 LoseIfUselessHackMarker (lhs);
1166 LoseIfUselessHackMarker (rhs);
1181void ChunkedArrayTextStore::RemoveMarkers (Marker*
const markerArray[],
size_t markerCount)
1183#if qUseLRUCacheForRecentlyLookedUpMarkers
1186 for (vector<MarkerOwner*>::const_iterator i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1187 GetAMOH (*i)->ClearCache ();
1190 Assert (markerCount == 0 or markerArray != NULL);
1197 for (
size_t i = 0; i < markerCount; ++i) {
1198 Assert (not OurStuff (markerArray[i])->fIsHackMarker);
1199 OurStuff (markerArray[i])->fIsHackMarker =
true;
1200 OurStuff (markerArray[i])->fIsDeletedMarker =
true;
1201#if qKeepChunkedArrayStatistics
1202 Assert (GetAMOH (markerArray[i])->fTotalMarkersPresent >= 1);
1203 GetAMOH (markerArray[i])->fTotalMarkersPresent -= 1;
1207 for (
size_t i = 0; i < markerCount; ++i) {
1208 Marker* marker = markerArray[i];
1209 if (marker->fTextStoreHook != NULL) {
1211 Assert (OurStuff (markerArray[i])->fIsHackMarker);
1212 RemoveMarker1 (marker);
1213 SetMarkerOwner_ (marker, NULL);
1215 delete ((ChunkedArrayMarkerHook*)marker->fTextStoreHook);
1216 marker->fTextStoreHook = NULL;
1221void ChunkedArrayTextStore::PreRemoveMarker (Marker* marker)
1224 Require (not OurStuff (marker)->fIsPreRemoved);
1225 OurStuff (marker)->fIsPreRemoved =
true;
1228void ChunkedArrayTextStore::RemoveMarker1 (Marker* marker)
1240 Marker* parent = OurStuff (marker)->fParent;
1241 Marker* ourLeftSibling = OurStuff (parent)->fFirstSubMarker;
1242 if (ourLeftSibling == marker) {
1243 ourLeftSibling = NULL;
1247 for (; OurStuff (ourLeftSibling)->fNextSubMarker != marker; ourLeftSibling = OurStuff (ourLeftSibling)->fNextSubMarker) {
1251 Assert (ourLeftSibling == NULL or OurStuff (ourLeftSibling)->fNextSubMarker == marker);
1257 if (ourLeftSibling == NULL) {
1258 Assert (OurStuff (parent)->fFirstSubMarker == marker);
1259 OurStuff (parent)->fFirstSubMarker = OurStuff (marker)->fNextSubMarker;
1262 Assert (OurStuff (ourLeftSibling)->fNextSubMarker == marker);
1263 OurStuff (ourLeftSibling)->fNextSubMarker = OurStuff (marker)->fNextSubMarker;
1265 OurStuff (marker)->fNextSubMarker = NULL;
1266 Assert (OurStuff (marker)->fParent == parent);
1267 OurStuff (marker)->fParent = NULL;
1274 size_t moveCount = 0;
1275 for (Marker* markerToMove = OurStuff (marker)->fFirstSubMarker; markerToMove != NULL;) {
1278 Marker* nextMarkerToMove = OurStuff (markerToMove)->fNextSubMarker;
1279 OurStuff (markerToMove)->fNextSubMarker = NULL;
1280 OurStuff (markerToMove)->fParent = NULL;
1281 AddMarker1 (markerToMove, parent,
false);
1282 markerToMove = nextMarkerToMove;
1285 if (moveCount > 1) {
1286 PossiblyAddHackMarkers (parent);
1295 for (Marker* hmi = OurStuff (parent)->fFirstSubMarker; hmi != NULL;) {
1296 ChunkedArrayMarkerHook* hmiStuff = OurStuff (hmi);
1297 Marker* nexthmi = hmiStuff->fNextSubMarker;
1298 if (OurStuff (hmi)->fIsHackMarker) {
1299 if (AllHackMarkers (hmi)) {
1300 GetAMOH (hmi)->FreeHackTree (hmi);
1303 LoseIfUselessHackMarker (hmi);
1312 for (Marker* hmi = parent; OurStuff (hmi)->fIsHackMarker;) {
1313 Marker* nextUp = OurStuff (hmi)->fParent;
1314 if (AllHackMarkers (hmi)) {
1316 GetAMOH (hmi)->FreeHackTree (hmi);
1326Marker* ChunkedArrayTextStore::AddHackMarkerHelper_ (Marker* insideMarker,
size_t start,
size_t length)
1328 HackMarker* marker =
new HackMarker ();
1333 Assert (marker->fTextStoreHook == NULL);
1334 marker->fTextStoreHook =
new ChunkedArrayMarkerHook ();
1335 Assert (OurStuff (marker)->fParent == NULL);
1336 OurStuff (marker)->fParent = insideMarker;
1337 SetMarkerOwner_ (marker, OurStuff (insideMarker)->fOwner);
1338 SetMarkerStart_ (marker, start);
1339 SetMarkerLength_ (marker, length);
1340 OurStuff (insideMarker)->AddToChildList (marker);
1342 Assert (not OurStuff (marker)->fIsHackMarker);
1343 OurStuff (marker)->fIsHackMarker =
true;
1344#if qKeepChunkedArrayStatistics
1345 ++GetAMOH (insideMarker)->fTotalHackMarkersAlloced;
1346 ++GetAMOH (insideMarker)->fTotalHackMarkersPresent;
1347 GetAMOH (insideMarker)->fPeakHackMarkersPresent =
1348 max (GetAMOH (insideMarker)->fPeakHackMarkersPresent, GetAMOH (insideMarker)->fTotalHackMarkersPresent);
1360void ChunkedArrayTextStore::LoseIfUselessHackMarker (Marker* potentiallyUselessHackMarker)
1363 Assert (OurStuff (potentiallyUselessHackMarker)->fIsHackMarker);
1365 Marker* firstChild = OurStuff (potentiallyUselessHackMarker)->fFirstSubMarker;
1367 bool truelyUseless = (firstChild == NULL) or (OurStuff (firstChild)->fNextSubMarker == NULL);
1375 if (firstChild != NULL and OurStuff (firstChild)->fNextSubMarker == NULL) {
1376 Assert (truelyUseless);
1377 Marker* goodParent = OurStuff (potentiallyUselessHackMarker)->fParent;
1378 Assert (OurStuff (firstChild)->fParent == potentiallyUselessHackMarker);
1379 OurStuff (firstChild)->fParent = goodParent;
1380 OurStuff (firstChild)->fNextSubMarker = OurStuff (goodParent)->fFirstSubMarker;
1381 OurStuff (goodParent)->fFirstSubMarker = firstChild;
1382 OurStuff (potentiallyUselessHackMarker)->fFirstSubMarker = NULL;
1386 if (truelyUseless) {
1387 GetAMOH (potentiallyUselessHackMarker)->FreeHackTree (potentiallyUselessHackMarker);
1391void ChunkedArrayTextStore::SetMarkerRange (Marker* marker,
size_t start,
size_t end)
noexcept
1394#if qUseLRUCacheForRecentlyLookedUpMarkers
1395 GetAMOH (marker)->ClearCache ();
1409 Assert (start >= 0);
1411 Assert (start <= end);
1414 size_t len = end - start;
1417 if (GetMarkerStart_ (marker) != start or GetMarkerLength_ (marker) != len) {
1423 Marker* parent = OurStuff (marker)->fParent;
1425 Assert (QUICK_Contains (*marker, *parent));
1426 if (Contains (start, end, *parent)) {
1429 for (Marker* mi = OurStuff (marker)->fFirstSubMarker; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1430 Assert (QUICK_Contains (*mi, *marker));
1434 SetMarkerStart_ (marker, start);
1435 SetMarkerLength_ (marker, len);
1441 Marker* prevMarker = NULL;
1442 for (Marker* mi = OurStuff (marker)->fFirstSubMarker; mi != NULL;) {
1443 Marker* nextMarker = OurStuff (mi)->fNextSubMarker;
1444 if (not QUICK_Contains (*mi, *marker)) {
1445 if (prevMarker == NULL) {
1446 Assert (OurStuff (marker)->fFirstSubMarker == mi);
1447 OurStuff (marker)->fFirstSubMarker = OurStuff (mi)->fNextSubMarker;
1450 Assert (OurStuff (prevMarker)->fNextSubMarker == mi);
1451 OurStuff (prevMarker)->fNextSubMarker = nextMarker;
1453 OurStuff (mi)->fNextSubMarker = NULL;
1454 OurStuff (mi)->fParent = NULL;
1455 AddMarker1 (mi, parent,
false);
1466 RemoveMarker (marker);
1467 AddMarker (marker, start, len, owner);
1472struct StackContext {
1473 const Marker* saved_belowHere;
1476void ChunkedArrayTextStore::CollectAllMarkersInRangeInto (
size_t from,
size_t to,
const MarkerOwner* owner, MarkerSink& output)
const
1479 Require (from <= to);
1488 if (owner == kAnyMarkerOwner) {
1489 for (vector<MarkerOwner*>::const_iterator i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1490 CollectAllMarkersInRangeInto_Helper_MO (from, to, *i, output);
1494#if qUseLRUCacheForRecentlyLookedUpMarkers
1495 ChunkedArrayMarkerOwnerHook* camoh = GetAMOH (owner);
1496 CollectLookupCacheElt* cacheItem = camoh->LookupElement (CollectLookupCacheElt::COMPARE_ITEM (from, to));
1497 if (cacheItem != NULL) {
1498 for (vector<Marker*>::const_iterator i = cacheItem->fMarkers.begin (); i != cacheItem->fMarkers.end (); ++i) {
1499 if (not OurStuff (*i)->fIsPreRemoved) {
1505 if (cacheItem == NULL and (to - from) <= 3) {
1506 cacheItem = camoh->AddNew (CollectLookupCacheElt::COMPARE_ITEM (from, to));
1507 cacheItem->fFrom = from;
1508 cacheItem->fTo = to;
1509 cacheItem->fMarkers.clear ();
1510 CollectAllMarkersInRangeInto_Helper_MO (from, to, owner, output, cacheItem);
1514 CollectAllMarkersInRangeInto_Helper_MO (from, to, owner, output);
1518void ChunkedArrayTextStore::CollectAllMarkersInRangeInto_Helper_MO (
size_t from,
size_t to,
const MarkerOwner* owner, MarkerSink& output
1519#
if qUseLRUCacheForRecentlyLookedUpMarkers
1521 CollectLookupCacheElt* fillingCache
1525 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook);
1527 const Marker* belowHere = &camoh->fRootMarker;
1528 size_t stackDepth = 0;
1533 Marker* mi = OurStuff (belowHere)->fFirstSubMarker;
1534 ChunkedArrayMarkerHook* mio = mi == NULL ? NULL : OurStuff (mi);
1535 for (; mi != NULL; (mi = mio->fNextSubMarker), (mio = mi == NULL ? NULL : OurStuff (mi))) {
1538 Assert (mio == OurStuff (mi));
1539 Assert (QUICK_Overlap (mio, from, to) == QUICK_Overlap (*mi, from, to));
1540 if (QUICK_Overlap (mio, from, to)) {
1541 if (not mio->fIsHackMarker and not mio->fIsPreRemoved) {
1542#if qUseLRUCacheForRecentlyLookedUpMarkers
1543 if (fillingCache != NULL) {
1544 fillingCache->fMarkers.push_back (mi);
1550 stack.GrowToSize (stackDepth + 1);
1551 stack[stackDepth].saved_belowHere = belowHere;
1552 stack[stackDepth].saved_mi = mi;
1557 Assert (stackDepth > 0);
1559 belowHere = stack[stackDepth].saved_belowHere;
1560 mi = stack[stackDepth].saved_mi;
1562 mio = OurStuff (mi);
1565 if (stackDepth != 0) {
1567 goto AfterCallPoint;
1571ChunkedArrayTextStore::ChunkAndOffset ChunkedArrayTextStore::FindChunkIndex_ (
size_t charPos)
const
1573 Assert (charPos >= 0);
1574 Assert (charPos <= GetEnd ());
1575 size_t totalChunks = fTextChunks.size ();
1576 size_t bytePosSoFar = 0;
1591 if (charPos >= fCachedChunkIndexesOffset) {
1592 startAt = fCachedChunkIndex;
1593 Assert (fCachedChunkIndexesOffset >= 0);
1594 bytePosSoFar = fCachedChunkIndexesOffset;
1596 for (
size_t i = startAt; i < totalChunks; ++i) {
1598 size_t curChunkSize = fTextChunks[i]->GetLength ();
1599 if (bytePosSoFar + curChunkSize > charPos) {
1600 Assert (charPos >= bytePosSoFar + 0);
1602 fCachedChunkIndex = i;
1603 fCachedChunkIndexesOffset = bytePosSoFar + 0;
1604 return (ChunkAndOffset (i, charPos - bytePosSoFar));
1606 bytePosSoFar += curChunkSize;
1608 return (ChunkAndOffset (totalChunks, 0));
1611void ChunkedArrayTextStore::AdjustMarkersForInsertAfter (
size_t after,
size_t howMany)
1613 for (
auto i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1614 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> ((*i)->fTextStoreHook);
1616 AdjustMarkersForInsertAfter1 (after, howMany, &camoh->fRootMarker);
1620void ChunkedArrayTextStore::AdjustMarkersForInsertAfter1 (
size_t after,
size_t howMany, Marker* startAt)
1625 size_t stackDepth = 0;
1636 size_t start = GetMarkerStart_ (startAt);
1637 size_t len = GetMarkerLength_ (startAt);
1638 size_t end = start + len;
1639 if (after < start) {
1640 SetMarkerStart_ (startAt, start + howMany);
1642 else if (after >= start and after < end) {
1643 SetMarkerLength_ (startAt, len + howMany);
1646 Assert (after >= end);
1647 if (stackDepth == 0) {
1651 goto AfterCallPoint;
1659 for (mi = OurStuff (startAt)->fFirstSubMarker; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1661 stack.GrowToSize (stackDepth + 1);
1662 stack[stackDepth] = mi;
1667 Assert (stackDepth > 0);
1669 mi = stack[stackDepth];
1671 if (stackDepth != 0) {
1673 goto AfterCallPoint;
1677void ChunkedArrayTextStore::AdjustMarkersForDeleteAfter (
size_t after,
size_t howMany)
1679 for (
auto i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1680 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> ((*i)->fTextStoreHook);
1682 AdjustMarkersForDeleteAfter1 (after, howMany, &camoh->fRootMarker);
1686void ChunkedArrayTextStore::AdjustMarkersForDeleteAfter1 (
size_t after,
size_t howMany, Marker* startAt)
1691 size_t stackDepth = 0;
1701 size_t start = GetMarkerStart_ (startAt);
1702 size_t len = GetMarkerLength_ (startAt);
1703 size_t end = start + len;
1704 if (after < start) {
1706 if (howMany + after <= start) {
1707 Assert (start >= howMany + 0);
1708 SetMarkerStart_ (startAt, start - howMany);
1711 Assert (howMany > (start - after));
1712 size_t deleteNCharsOffFront = howMany - (start - after);
1713 size_t moveFront = howMany - deleteNCharsOffFront;
1714 SetMarkerStart_ (startAt, start - moveFront);
1718 SetMarkerLength_ (startAt, (len > deleteNCharsOffFront) ? (len - deleteNCharsOffFront) : 0);
1721 else if (after >= start and after < end) {
1722 size_t newEnd = end;
1723 if (end - after < howMany) {
1729 Assert (newEnd >= start);
1730 size_t newLen = newEnd - start;
1731 SetMarkerLength_ (startAt, newLen);
1734 Assert (after >= end);
1735 if (stackDepth == 0) {
1739 goto AfterCallPoint;
1747 for (mi = OurStuff (startAt)->fFirstSubMarker; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1749 stack.GrowToSize (stackDepth + 1);
1750 stack[stackDepth] = mi;
1755 Assert (stackDepth > 0);
1757 mi = stack[stackDepth];
1760 if (stackDepth != 0) {
1762 goto AfterCallPoint;
1766bool ChunkedArrayTextStore::AllSubMarkersAreHackMarkerTrees (
const Marker* m)
1769 Assert (OurStuff (m)->fIsHackMarker);
1772 size_t stackDepth = 0;
1780 for (Marker* mi = OurStuff (m)->fFirstSubMarker; mi != NULL;) {
1781 ChunkedArrayMarkerHook* misStuff = OurStuff (mi);
1782 Assert (misStuff->fParent == m);
1783 if (not misStuff->fIsHackMarker) {
1786 mi = misStuff->fNextSubMarker;
1789 Marker* mi = OurStuff (m)->fFirstSubMarker;
1790 for (; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1791 Assert (OurStuff (mi)->fIsHackMarker);
1793 stack.GrowToSize (stackDepth + 1);
1794 stack[stackDepth] = mi;
1799 Assert (stackDepth > 0);
1801 mi = stack[stackDepth];
1804 if (stackDepth != 0) {
1806 goto AfterCallPoint;
1811#if qStroika_Foundation_Debug_AssertionsChecked
1812void ChunkedArrayTextStore::Invariant_ ()
const
1814 TextStore::Invariant_ ();
1815 for (
auto i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1816 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> ((*i)->fTextStoreHook);
1818 WalkSubTreeAndCheckInvariants (&camoh->fRootMarker);
1823#if qStroika_Foundation_Debug_AssertionsChecked
1824void ChunkedArrayTextStore::WalkSubTreeAndCheckInvariants (
const Marker* m)
const
1828 for (
const Marker* subMarker = OurStuff (m)->fFirstSubMarker; subMarker != NULL; subMarker = OurStuff (subMarker)->fNextSubMarker) {
1831 Assert (OurStuff (subMarker)->fParent == m);
1832 Assert (QUICK_Contains (*subMarker, *m));
1833#if qHeavyMarkerDebugging
1834 Assert (not OurStuff (subMarker)->fIsHackMarker or OurStuff (subMarker)->fFirstSubMarker != NULL);
1836 WalkSubTreeAndCheckInvariants (subMarker);
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define RequireNotNull(p)
#define AssertMember(p, c)
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
LRUCache implements a simple least-recently-used caching strategy, with optional hashing (of keys) to...
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...