4#include "Stroika/Frameworks/StroikaPreComp.h"
6#include "ChunkedArrayTextStore.h"
9using namespace Stroika::Foundation::Memory;
11using namespace Stroika::Frameworks;
12using namespace Stroika::Frameworks::Led;
14class ChunkedArrayTextStore::TextChunk {
16 TextChunk () =
default;
17 TextChunk (
const Led_tChar* copyFrom,
size_t bytesToCopy);
21 kTextChunkSize = (4096 -
sizeof (size_t) - 8) /
sizeof (Led_tChar)
30 nonvirtual
size_t GetLength () const noexcept;
31 nonvirtual
size_t GetBytesCanAccommodate () const noexcept;
32 nonvirtual
void CopyOut (
size_t from,
size_t count, Led_tChar* buffer) const noexcept;
33 nonvirtual const Led_tChar* PeekAfter (
size_t charPos) const noexcept;
34 nonvirtual
void InsertAfter (const Led_tChar* what,
size_t howMany,
size_t after) noexcept;
35 nonvirtual
void DeleteAfter (
size_t howMany,
size_t after) noexcept;
38 size_t fTotalTcharsUsed{0};
39 Led_tChar fData[kTextChunkSize];
43inline ChunkedArrayTextStore::TextChunk::TextChunk (
const Led_tChar* copyFrom,
size_t bytesToCopy)
44 : fTotalTcharsUsed{bytesToCopy}
46 Assert (bytesToCopy <= kTextChunkSize);
48 (void)::memcpy (fData, copyFrom, bytesToCopy *
sizeof (Led_tChar));
50inline size_t ChunkedArrayTextStore::TextChunk::GetLength () const noexcept
52 return (fTotalTcharsUsed);
54inline size_t ChunkedArrayTextStore::TextChunk::GetBytesCanAccommodate () const noexcept
56 return (kTextChunkSize - fTotalTcharsUsed);
58inline void ChunkedArrayTextStore::TextChunk::CopyOut (
size_t from,
size_t count, Led_tChar* buffer)
const noexcept
61 Assert (from + count <= fTotalTcharsUsed);
62 (void)::memcpy (buffer, &fData[from], count *
sizeof (Led_tChar));
64inline const Led_tChar* ChunkedArrayTextStore::TextChunk::PeekAfter (
size_t charPos)
const noexcept
66 Assert (charPos >= 0);
67 Assert (charPos < fTotalTcharsUsed);
68 return (&fData[charPos]);
70inline void ChunkedArrayTextStore::TextChunk::InsertAfter (
const Led_tChar* what,
size_t howMany,
size_t after)
noexcept
72 Assert (what != 0 or howMany == 0);
74 Assert (after <= fTotalTcharsUsed);
75 Assert (after + howMany <= kTextChunkSize);
80 Assert (fTotalTcharsUsed >= after);
81 size_t bytesToMove = fTotalTcharsUsed - after;
82 if (bytesToMove != 0) {
83 (void)memmove (&fData[after + howMany], &fData[after], bytesToMove *
sizeof (Led_tChar));
85 (void)::memcpy (&fData[after], what, howMany *
sizeof (Led_tChar));
86 fTotalTcharsUsed += howMany;
88inline void ChunkedArrayTextStore::TextChunk::DeleteAfter (
size_t howMany,
size_t after)
noexcept
90 Require (after + howMany <= fTotalTcharsUsed);
91 size_t bytesToMove = fTotalTcharsUsed - (after + howMany);
92 if (bytesToMove != 0) {
93 (void)::memmove (&fData[after], &fData[after + howMany], bytesToMove *
sizeof (Led_tChar));
95 fTotalTcharsUsed -= howMany;
106const size_t kEnufChildrenToApplyHackMarkers = 50;
111 ChunkedArrayMarkerHook () =
default;
115 virtual size_t GetStart ()
const override;
116 virtual size_t GetEnd ()
const override;
117 virtual size_t GetLength ()
const override;
118 virtual void GetStartEnd (
size_t* start,
size_t* end)
const override;
120 nonvirtual
void AddToChildList (Marker* marker);
121 nonvirtual
size_t CountChildren ()
const;
122 nonvirtual
bool CountChildrenMoreThan (
size_t n)
const;
127 Marker* fFirstSubMarker;
128 Marker* fNextSubMarker;
130 Marker* fParent{
nullptr};
131 bool fIsHackMarker : 1 {
false};
132 bool fIsDeletedMarker : 1 {
false};
133 bool fIsPreRemoved : 1 {
false};
142 HackMarker () =
default;
145MarkerOwner* ChunkedArrayMarkerHook::GetOwner ()
const
152size_t ChunkedArrayMarkerHook::GetStart ()
const
154 Assert (fStart < 0x8000000);
160size_t ChunkedArrayMarkerHook::GetEnd ()
const
162 Assert (fStart < 0x8000000);
163 Assert (fLength < 0x8000000);
164 return fStart + fLength;
167size_t ChunkedArrayMarkerHook::GetLength ()
const
169 Assert (fLength < 0x8000000);
173void ChunkedArrayMarkerHook::GetStartEnd (
size_t* start,
size_t* end)
const
175 Assert (fStart < 0x8000000);
176 Assert (fLength < 0x8000000);
180 *end = fStart + fLength;
188static inline ChunkedArrayMarkerHook* OurStuff (
const Marker* marker)
192 AssertMember (marker->fTextStoreHook, ChunkedArrayMarkerHook);
194 return (ChunkedArrayMarkerHook*)marker->fTextStoreHook;
197inline void ChunkedArrayMarkerHook::AddToChildList (Marker* marker)
200 OurStuff (marker)->fNextSubMarker = fFirstSubMarker;
201 fFirstSubMarker = marker;
203inline size_t ChunkedArrayMarkerHook::CountChildren ()
const
205 size_t nChildren = 0;
206 for (
auto curChild = fFirstSubMarker; curChild != NULL; curChild = OurStuff (curChild)->fNextSubMarker) {
211inline bool ChunkedArrayMarkerHook::CountChildrenMoreThan (
size_t n)
const
213 size_t nChildren = 0;
214 for (
auto curChild = fFirstSubMarker; curChild != NULL; curChild = OurStuff (curChild)->fNextSubMarker) {
216 if (nChildren >= n) {
220 return nChildren >= n;
222inline bool ChunkedArrayTextStore::AllHackMarkers (
const Marker* m)
225 return (OurStuff (m)->fIsHackMarker and (OurStuff (m)->fFirstSubMarker == NULL or AllSubMarkersAreHackMarkerTrees (m)));
227inline ChunkedArrayTextStore::TextChunk* ChunkedArrayTextStore::AtomicAddChunk (
size_t atArrayPos)
229 TextChunk* t =
new TextChunk ();
233 fTextChunks.insert (fTextChunks.begin () + atArrayPos, t);
243static inline size_t GetMarkerStart_ (Marker* m)
246 Ensure (OurStuff (m)->fStart == m->GetStart ());
247 return OurStuff (m)->fStart;
249static inline void SetMarkerStart_ (Marker* m,
size_t s)
251 OurStuff (m)->fStart = s;
253static inline size_t GetMarkerLength_ (Marker* m)
256 Ensure (OurStuff (m)->fLength == m->GetLength ());
257 return OurStuff (m)->fLength;
259static inline void SetMarkerLength_ (Marker* m,
size_t s)
261 OurStuff (m)->fLength = s;
263static inline void SetMarkerOwner_ (Marker* m,
MarkerOwner* o)
265 OurStuff (m)->fOwner = o;
268static inline bool QUICK_Overlap (ChunkedArrayMarkerHook* h,
size_t from,
size_t to)
274 size_t start = h->fStart;
278 size_t end = start + h->fLength;
280 if ((from <= end) and (start <= to)) {
284 size_t a = end - from;
285 size_t b = end - start;
286 overlapSize = min (a, b);
289 size_t a = to - from;
290 size_t b = to - start;
291 overlapSize = min (a, b);
293 if (overlapSize == 0) {
304static inline bool QUICK_Overlap (
const Marker& m,
size_t from,
size_t to)
306 bool result = QUICK_Overlap (OurStuff (&m), from, to);
307 Assert (result == TextStore::Overlap (m, from, to));
310static inline bool QUICK_Contains (
size_t containedStart,
size_t containedEnd,
size_t containerStart,
size_t containerEnd)
312 return (containedStart >= containerStart) and (containerEnd >= containedEnd);
314static inline bool QUICK_Contains (
const Marker& containedMarker,
const Marker& containerMarker)
316 ChunkedArrayMarkerHook* h = OurStuff (&containerMarker);
317 size_t containerStart = h->fStart;
318 size_t containerEnd = containerStart + h->fLength;
320 ChunkedArrayMarkerHook* h1 = OurStuff (&containedMarker);
321 size_t containedStart = h1->fStart;
322 size_t containedEnd = containedStart + h1->fLength;
324 bool result = QUICK_Contains (containedStart, containedEnd, containerStart, containerEnd);
325 Assert (result == Contains (containedMarker, containerMarker));
329#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
330struct ChunkedArrayTextStore::CollectLookupCacheElt {
331 vector<Marker*> fMarkers;
335 struct COMPARE_ITEM {
336 COMPARE_ITEM (
size_t from,
size_t to)
346 nonvirtual
void Clear ()
348 fFrom =
static_cast<size_t> (-1);
350 static bool Equal (
const CollectLookupCacheElt& lhs,
const COMPARE_ITEM& rhs)
352 return lhs.fFrom == rhs.fFrom and lhs.fTo == rhs.fTo;
357class ChunkedArrayMarkerOwnerHook :
public MarkerOwner::HookData {
359 using inherited = MarkerOwner::HookData;
362 ChunkedArrayMarkerOwnerHook (
MarkerOwner* mo,
size_t len)
364#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
369#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
370 , fTotalMarkersPresent{0}
371 , fTotalHackMarkersPresent{0}
372 , fPeakTotalMarkersPresent{0}
373 , fPeakHackMarkersPresent{0}
374 , fTotalHackMarkersAlloced{0}
377 Assert (fRootMarker.fTextStoreHook == NULL);
378 fRootMarker.fTextStoreHook =
new ChunkedArrayMarkerHook ();
379 SetMarkerOwner_ (&fRootMarker, mo);
380 SetMarkerStart_ (&fRootMarker, 0);
381 SetMarkerLength_ (&fRootMarker, len);
383 ~ChunkedArrayMarkerOwnerHook ()
385#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
386 Require (fTotalMarkersPresent == 0);
409 for (Marker* mi = OurStuff (&fRootMarker)->fFirstSubMarker; mi != NULL; mi = OurStuff (&fRootMarker)->fFirstSubMarker) {
410 Assert (AllHackMarkers (mi));
416#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
417 Assert (fTotalHackMarkersPresent == 0);
421 Assert (OurStuff (&fRootMarker)->fFirstSubMarker == NULL);
423 if (fRootMarker.fTextStoreHook != NULL) {
424 SetMarkerOwner_ (&fRootMarker, NULL);
426 delete ((ChunkedArrayMarkerHook*)fRootMarker.fTextStoreHook);
429#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
431 using CollectLookupCacheElt = ChunkedArrayTextStore::CollectLookupCacheElt;
436 nonvirtual
void ClearCache ()
438 fCache.ClearCache ();
440 nonvirtual CollectLookupCacheElt* LookupElement (
const CollectLookupCacheElt::COMPARE_ITEM& item)
442 return fCache.LookupElement (item);
444 nonvirtual CollectLookupCacheElt* AddNew (
const CollectLookupCacheElt::COMPARE_ITEM& item)
446 return fCache.AddNew (item);
454 inline bool AllHackMarkers (
const Marker* m)
457 return (OurStuff (m)->fIsHackMarker and (OurStuff (m)->fFirstSubMarker == NULL or AllSubMarkersAreHackMarkerTrees (m)));
461 nonvirtual
bool AllSubMarkersAreHackMarkerTrees (
const Marker* m)
464 Assert (OurStuff (m)->fIsHackMarker);
467 size_t stackDepth = 0;
475 for (
auto mi = OurStuff (m)->fFirstSubMarker; mi != NULL;) {
476 ChunkedArrayMarkerHook* misStuff = OurStuff (mi);
477 Assert (misStuff->fParent == m);
478 if (not misStuff->fIsHackMarker) {
481 mi = misStuff->fNextSubMarker;
484 auto mi = OurStuff (m)->fFirstSubMarker;
485 for (; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
486 Assert (OurStuff (mi)->fIsHackMarker);
488 stack.GrowToSize (stackDepth + 1);
489 stack[stackDepth] = mi;
494 Assert (stackDepth > 0);
496 mi = stack[stackDepth];
499 if (stackDepth != 0) {
507 nonvirtual
void FreeHackTree (Marker* m)
510 Assert (OurStuff (m)->fIsHackMarker);
513 Marker* parent = OurStuff (m)->fParent;
515 Marker* prevMarker = NULL;
516 for (
auto mi = OurStuff (parent)->fFirstSubMarker; mi != NULL; (prevMarker = mi), (mi = OurStuff (mi)->fNextSubMarker)) {
517 Assert (OurStuff (mi)->fParent == parent);
519 if (prevMarker == NULL) {
520 Assert (OurStuff (parent)->fFirstSubMarker == mi);
521 OurStuff (parent)->fFirstSubMarker = OurStuff (mi)->fNextSubMarker;
524 Assert (OurStuff (prevMarker)->fNextSubMarker == mi);
525 OurStuff (prevMarker)->fNextSubMarker = OurStuff (mi)->fNextSubMarker;
527 OurStuff (mi)->fNextSubMarker = NULL;
535 nonvirtual
void FreeHackTree1 (Marker* m)
538 Assert (OurStuff (m)->fIsHackMarker);
540 for (Marker* mi = OurStuff (m)->fFirstSubMarker; mi != NULL;) {
541 Marker* nextMI = OurStuff (mi)->fNextSubMarker;
546 bool isDeletedMarker = OurStuff (m)->fIsDeletedMarker;
547 delete ((ChunkedArrayMarkerHook*)m->fTextStoreHook);
549 if (isDeletedMarker) {
550 m->fTextStoreHook = NULL;
554 m->fTextStoreHook = (ChunkedArrayMarkerHook*)666;
557#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
558 Assert (fTotalHackMarkersPresent > 0);
559 --fTotalHackMarkersPresent;
567#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
569 unsigned long fTotalMarkersPresent;
570 unsigned long fTotalHackMarkersPresent;
571 unsigned long fPeakTotalMarkersPresent;
572 unsigned long fPeakHackMarkersPresent;
573 unsigned long fTotalHackMarkersAlloced;
577inline ChunkedArrayMarkerOwnerHook* GetAMOH (
const MarkerOwner* mo)
581 RequireNotNull (
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (mo->fTextStoreHook));
582 return dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (mo->fTextStoreHook);
584inline ChunkedArrayMarkerOwnerHook* GetAMOH (ChunkedArrayMarkerHook* moh)
587 return GetAMOH (moh->fOwner);
589inline ChunkedArrayMarkerOwnerHook* GetAMOH (Marker* m)
591 return GetAMOH (OurStuff (m));
611ChunkedArrayTextStore::ChunkedArrayTextStore ()
613 fTextStoreHook =
new ChunkedArrayMarkerOwnerHook (
this, 2);
616ChunkedArrayTextStore::~ChunkedArrayTextStore ()
618 Require (GetMarkerOwners ().size () == 1);
627 delete fTextStoreHook;
628 fTextStoreHook = NULL;
631 for (
size_t i = 0; i < fTextChunks.size (); i++) {
632 delete fTextChunks[i];
640TextStore* ChunkedArrayTextStore::ConstructNewTextStore ()
const
642 return new ChunkedArrayTextStore ();
645void ChunkedArrayTextStore::AddMarkerOwner (
MarkerOwner* owner)
648 Require (owner->fTextStoreHook == NULL);
649 inherited::AddMarkerOwner (owner);
651 owner->fTextStoreHook =
new ChunkedArrayMarkerOwnerHook (owner, GetLength () + 2);
658 inherited::RemoveMarkerOwner (owner);
663void ChunkedArrayTextStore::RemoveMarkerOwner (
MarkerOwner* owner)
667 RequireNotNull (
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook));
668#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
670 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook);
671 Require (camoh->fTotalMarkersPresent == 0);
680 if (camoh->fTotalMarkersPresent != 0) {
681 vector<Marker*> markersWhichShouldHaveBeenDeleted;
682 VectorMarkerSink tmp{&markersWhichShouldHaveBeenDeleted};
683 CollectAllMarkersInRangeInto (0, GetEnd () + 2, owner, tmp);
688 delete owner->fTextStoreHook;
689 owner->fTextStoreHook = NULL;
690 inherited::RemoveMarkerOwner (owner);
693void ChunkedArrayTextStore::CopyOut (
size_t from,
size_t count, Led_tChar* buffer)
const noexcept
699 Require (from + count <= GetEnd ());
701 ChunkAndOffset chunkIdx = FindChunkIndex (from);
702 for (
size_t bytesToGo = count; bytesToGo != 0;) {
703 Assert (chunkIdx.fChunk >= 0);
704 Assert (chunkIdx.fChunk < fTextChunks.size ());
706 TextChunk* t = fTextChunks[chunkIdx.fChunk];
708 size_t copyFromThisGuy = min (bytesToGo, t->GetLength () - (chunkIdx.fOffset));
709 t->CopyOut (chunkIdx.fOffset, copyFromThisGuy, &buffer[count - bytesToGo]);
712 chunkIdx.fOffset = 0;
714 bytesToGo -= copyFromThisGuy;
718void ChunkedArrayTextStore::ReplaceWithoutUpdate (
size_t from,
size_t to,
const Led_tChar* withWhat,
size_t withWhatCount)
720#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
721 for (vector<MarkerOwner*>::const_iterator i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
722 GetAMOH (*i)->ClearCache ();
726 if (from != to or withWhatCount != 0) {
757 DeleteAfter_ (to - from, from);
759 if (withWhatCount != 0) {
760 InsertAfter_ (withWhat, withWhatCount, from);
765void ChunkedArrayTextStore::InsertAfter_ (
const Led_tChar* what,
size_t howMany,
size_t after)
767 Assert (howMany > 0);
768 Assert (what != NULL);
770 Assert (howMany > 0);
771 Assert (what != NULL);
773 ChunkAndOffset chunkIdx = FindChunkIndex (after);
780 if (chunkIdx.fChunk >= fTextChunks.size ()) {
781 if (fTextChunks.size () == 0) {
782 (void)AtomicAddChunk (0);
788 Assert (chunkIdx.fChunk >= 1);
789 TextChunk* preChunk = fTextChunks[chunkIdx.fChunk - 1];
790 if (preChunk->GetBytesCanAccommodate () == 0) {
791 (void)AtomicAddChunk (fTextChunks.size ());
795 chunkIdx.fOffset = preChunk->GetLength ();
799 TextChunk* t = fTextChunks[chunkIdx.fChunk];
806 size_t bytesXfered = 0;
808 if (t->GetBytesCanAccommodate () >= howMany) {
812 t->InsertAfter (what, howMany, chunkIdx.fOffset);
813 bytesXfered += howMany;
826 if (chunkIdx.fChunk == fTextChunks.size () - 1) {
827 (void)AtomicAddChunk (chunkIdx.fChunk + 1);
829 TextChunk* followingChunk = fTextChunks[chunkIdx.fChunk + 1];
831 size_t splitPoint = chunkIdx.fOffset;
832 size_t bytesToShift = t->GetLength () - (splitPoint);
833 const Led_tChar* peekAfter = (bytesToShift == 0) ? NULL : t->PeekAfter (splitPoint);
834 if (followingChunk->GetBytesCanAccommodate () >= bytesToShift) {
835 followingChunk->InsertAfter (peekAfter, bytesToShift, 0);
842 followingChunk = AtomicAddChunk (chunkIdx.fChunk + 1);
843 followingChunk->InsertAfter (peekAfter, bytesToShift, 0);
845 t->DeleteAfter (bytesToShift, splitPoint);
854 size_t bytesToGo = howMany;
855 size_t copyFromThisGuy = min (bytesToGo, t->GetBytesCanAccommodate ());
856 t->InsertAfter (&what[bytesXfered], copyFromThisGuy, chunkIdx.fOffset);
858 bytesToGo -= copyFromThisGuy;
859 bytesXfered += copyFromThisGuy;
861 for (; bytesToGo != 0;) {
863 if (chunkIdx.fChunk <= fTextChunks.size () - 1 and fTextChunks[chunkIdx.fChunk]->GetBytesCanAccommodate () >= bytesToGo) {
865 t = fTextChunks[chunkIdx.fChunk];
866 t->InsertAfter (&what[bytesXfered], bytesToGo, 0);
867 bytesXfered += bytesToGo;
868 bytesToGo -= bytesToGo;
869 Assert (bytesToGo == 0);
870 Assert (bytesXfered == howMany);
875 t = AtomicAddChunk (chunkIdx.fChunk);
877 copyFromThisGuy = min (bytesToGo, t->GetBytesCanAccommodate ());
878 t->InsertAfter (&what[bytesXfered], copyFromThisGuy, 0);
879 bytesToGo -= copyFromThisGuy;
880 bytesXfered += copyFromThisGuy;
886 fLength += bytesXfered;
887 AdjustMarkersForInsertAfter (after, bytesXfered);
891 Assert (howMany == bytesXfered);
892 fLength += bytesXfered;
893 AdjustMarkersForInsertAfter (after, bytesXfered);
896void ChunkedArrayTextStore::DeleteAfter_ (
size_t howMany,
size_t after)
899 Assert ((after) + howMany <= GetLength ());
900 Assert (howMany > 0);
902 ChunkAndOffset chunkIdx = FindChunkIndex (after);
903 for (
size_t bytesToGo = howMany; bytesToGo != 0;) {
905 TextChunk* t = fTextChunks[chunkIdx.fChunk];
909 size_t deleteFromThisGuy = min (bytesToGo, t->GetLength () - (chunkIdx.fOffset));
910 Assert (deleteFromThisGuy != 0);
911 t->DeleteAfter (deleteFromThisGuy, chunkIdx.fOffset);
912 bytesToGo -= deleteFromThisGuy;
913 fLength -= deleteFromThisGuy;
916 chunkIdx.fOffset = 0;
917 chunkIdx.fChunk += 1;
923 if (t->GetLength () == 0) {
924 chunkIdx.fChunk -= 1;
925 fTextChunks.erase (fTextChunks.begin () + chunkIdx.fChunk);
929 AdjustMarkersForDeleteAfter (after, howMany);
932void ChunkedArrayTextStore::AddMarker (Marker* marker,
size_t lhs,
size_t length,
MarkerOwner* owner)
936 Require (owner->PeekAtTextStore () ==
this);
937 Require (owner ==
this or IndexOf (GetMarkerOwners (), owner) != kBadIndex);
938 Require (marker->fTextStoreHook == NULL);
939 Require (lhs < 0x80000000);
940 Require (length < 0x80000000);
941 Require (lhs + length <= fLength + 1);
944 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook);
947#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
948 camoh->ClearCache ();
951 marker->fTextStoreHook =
new ChunkedArrayMarkerHook ();
954 SetMarkerOwner_ (marker, owner);
956 SetMarkerStart_ (marker, lhs);
957 SetMarkerLength_ (marker, length);
959 AddMarker1 (marker, &camoh->fRootMarker,
true);
961#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
962 ++camoh->fTotalMarkersPresent;
963 camoh->fPeakTotalMarkersPresent = max (camoh->fPeakTotalMarkersPresent, camoh->fTotalMarkersPresent);
968#ifndef qKeepTrackOfChildCountAndAvoidSomePossiblyAdds_
969#define qKeepTrackOfChildCountAndAvoidSomePossiblyAdds_ 1
972void ChunkedArrayTextStore::AddMarker1 (Marker* marker, Marker* insideMarker,
bool canAddHackMarkers)
976 Assert (marker != insideMarker);
979 Assert (QUICK_Contains (*marker, *insideMarker));
980 Assert (OurStuff (marker)->fParent == NULL);
981 Assert (OurStuff (marker)->fNextSubMarker == NULL);
984 size_t markerStart = GetMarkerStart_ (marker);
985 size_t markerEnd = markerStart + GetMarkerLength_ (marker);
999 Marker* specificInsideMarker = insideMarker;
1001#if qKeepTrackOfChildCountAndAvoidSomePossiblyAdds_
1002 size_t specificInsideMarkerChildCount = 0;
1004 Marker* prevMarker = NULL;
1005 for (Marker* curChild = OurStuff (specificInsideMarker)->fFirstSubMarker; curChild != NULL;
1006 (prevMarker = curChild), (curChild = OurStuff (curChild)->fNextSubMarker)) {
1007 Assert (marker != curChild);
1009#if qKeepTrackOfChildCountAndAvoidSomePossiblyAdds_
1010 ++specificInsideMarkerChildCount;
1025 size_t curChildStart = GetMarkerStart_ (curChild);
1026 size_t curChildEnd = curChildStart + GetMarkerLength_ (curChild);
1027 if (markerStart == curChildStart and markerEnd == curChildEnd and OurStuff (marker)->fFirstSubMarker == NULL) {
1028 Assert (QUICK_Contains (*marker, *curChild));
1033 Assert (OurStuff (marker)->fParent == NULL);
1034 OurStuff (marker)->fParent = OurStuff (curChild)->fParent;
1036 Assert (OurStuff (marker)->fFirstSubMarker == NULL);
1037 OurStuff (marker)->fFirstSubMarker = OurStuff (curChild)->fFirstSubMarker;
1039 Assert (OurStuff (marker)->fNextSubMarker == NULL);
1040 OurStuff (marker)->fNextSubMarker = OurStuff (curChild)->fNextSubMarker;
1043 if (prevMarker == NULL) {
1044 Assert (OurStuff (marker)->fParent == specificInsideMarker);
1045 Assert (OurStuff (specificInsideMarker)->fFirstSubMarker == curChild);
1046 OurStuff (specificInsideMarker)->fFirstSubMarker = marker;
1049 Assert (OurStuff (prevMarker)->fNextSubMarker == curChild);
1050 OurStuff (prevMarker)->fNextSubMarker = marker;
1054 OurStuff (curChild)->fNextSubMarker = OurStuff (marker)->fFirstSubMarker;
1055 OurStuff (marker)->fFirstSubMarker = curChild;
1056 OurStuff (curChild)->fFirstSubMarker = NULL;
1057 OurStuff (curChild)->fParent = marker;
1061 for (Marker* mm = OurStuff (marker)->fFirstSubMarker; mm != NULL; mm = OurStuff (mm)->fNextSubMarker) {
1062 Assert (OurStuff (mm)->fParent == curChild or (mm == curChild));
1063 OurStuff (mm)->fParent = marker;
1069 Assert (QUICK_Contains (*marker, *curChild) == QUICK_Contains (markerStart, markerEnd, curChildStart, curChildEnd));
1070 if (QUICK_Contains (markerStart, markerEnd, curChildStart, curChildEnd)) {
1071 specificInsideMarker = curChild;
1076#if qKeepTrackOfChildCountAndAvoidSomePossiblyAdds_
1077 if (specificInsideMarkerChildCount < kEnufChildrenToApplyHackMarkers) {
1078 canAddHackMarkers =
false;
1087 OurStuff (specificInsideMarker)->AddToChildList (marker);
1088 Assert (OurStuff (marker)->fParent == NULL);
1089 OurStuff (marker)->fParent = specificInsideMarker;
1092 if (canAddHackMarkers) {
1093 PossiblyAddHackMarkers (specificInsideMarker);
1097void ChunkedArrayTextStore::PossiblyAddHackMarkers (Marker* insideMarker)
1103 if (GetMarkerLength_ (insideMarker) >= 2 and OurStuff (insideMarker)->CountChildrenMoreThan (kEnufChildrenToApplyHackMarkers)) {
1104 size_t insideMarkerStart = GetMarkerStart_ (insideMarker);
1105 size_t insideMarkerEnd = insideMarkerStart + GetMarkerLength_ (insideMarker);
1106 size_t insideMarkerLength = insideMarkerEnd - insideMarkerStart;
1115 lhs = AddHackMarkerHelper_ (insideMarker, insideMarkerStart, insideMarkerLength / 2);
1116 size_t rhsStart = insideMarkerStart + insideMarkerLength / 2;
1117 rhs = AddHackMarkerHelper_ (insideMarker, rhsStart, insideMarkerEnd - rhsStart);
1121 Assert (OurStuff (insideMarker)->CountChildren () > 2);
1122 Marker* prevMarker = NULL;
1123 for (Marker* curMarker = OurStuff (insideMarker)->fFirstSubMarker; curMarker != NULL;) {
1124 Marker* nextMarker = OurStuff (curMarker)->fNextSubMarker;
1125 if (curMarker != lhs and curMarker != rhs) {
1126 DISABLE_COMPILER_MSC_WARNING_START (6011)
1127 if (QUICK_Contains (*curMarker, *lhs)) {
1130 OurStuff (prevMarker)->fNextSubMarker = OurStuff (curMarker)->fNextSubMarker;
1131 OurStuff (curMarker)->fNextSubMarker = NULL;
1132 Assert (OurStuff (curMarker)->fParent == insideMarker);
1133 OurStuff (curMarker)->fParent = NULL;
1134 AddMarker1 (curMarker, lhs,
false);
1136 curMarker = nextMarker;
1139 else if (QUICK_Contains (*curMarker, *rhs)) {
1142 OurStuff (prevMarker)->fNextSubMarker = OurStuff (curMarker)->fNextSubMarker;
1143 OurStuff (curMarker)->fNextSubMarker = NULL;
1144 Assert (OurStuff (curMarker)->fParent == insideMarker);
1145 OurStuff (curMarker)->fParent = NULL;
1146 AddMarker1 (curMarker, rhs,
false);
1148 curMarker = nextMarker;
1151 DISABLE_COMPILER_MSC_WARNING_END (6011)
1153 prevMarker = curMarker;
1154 curMarker = nextMarker;
1156 LoseIfUselessHackMarker (lhs);
1157 LoseIfUselessHackMarker (rhs);
1172void ChunkedArrayTextStore::RemoveMarkers (Marker*
const markerArray[],
size_t markerCount)
1174#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
1177 for (vector<MarkerOwner*>::const_iterator i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1178 GetAMOH (*i)->ClearCache ();
1181 Assert (markerCount == 0 or markerArray != NULL);
1188 for (
size_t i = 0; i < markerCount; ++i) {
1189 Assert (not OurStuff (markerArray[i])->fIsHackMarker);
1190 OurStuff (markerArray[i])->fIsHackMarker =
true;
1191 OurStuff (markerArray[i])->fIsDeletedMarker =
true;
1192#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
1193 Assert (GetAMOH (markerArray[i])->fTotalMarkersPresent >= 1);
1194 GetAMOH (markerArray[i])->fTotalMarkersPresent -= 1;
1198 for (
size_t i = 0; i < markerCount; ++i) {
1199 Marker* marker = markerArray[i];
1200 if (marker->fTextStoreHook != NULL) {
1202 Assert (OurStuff (markerArray[i])->fIsHackMarker);
1203 RemoveMarker1 (marker);
1204 SetMarkerOwner_ (marker, NULL);
1206 delete ((ChunkedArrayMarkerHook*)marker->fTextStoreHook);
1207 marker->fTextStoreHook = NULL;
1212void ChunkedArrayTextStore::PreRemoveMarker (Marker* marker)
1215 Require (not OurStuff (marker)->fIsPreRemoved);
1216 OurStuff (marker)->fIsPreRemoved =
true;
1219void ChunkedArrayTextStore::RemoveMarker1 (Marker* marker)
1231 Marker* parent = OurStuff (marker)->fParent;
1232 Marker* ourLeftSibling = OurStuff (parent)->fFirstSubMarker;
1233 if (ourLeftSibling == marker) {
1234 ourLeftSibling = NULL;
1238 for (; OurStuff (ourLeftSibling)->fNextSubMarker != marker; ourLeftSibling = OurStuff (ourLeftSibling)->fNextSubMarker) {
1242 Assert (ourLeftSibling == NULL or OurStuff (ourLeftSibling)->fNextSubMarker == marker);
1248 if (ourLeftSibling == NULL) {
1249 Assert (OurStuff (parent)->fFirstSubMarker == marker);
1250 OurStuff (parent)->fFirstSubMarker = OurStuff (marker)->fNextSubMarker;
1253 Assert (OurStuff (ourLeftSibling)->fNextSubMarker == marker);
1254 OurStuff (ourLeftSibling)->fNextSubMarker = OurStuff (marker)->fNextSubMarker;
1256 OurStuff (marker)->fNextSubMarker = NULL;
1257 Assert (OurStuff (marker)->fParent == parent);
1258 OurStuff (marker)->fParent = NULL;
1265 size_t moveCount = 0;
1266 for (Marker* markerToMove = OurStuff (marker)->fFirstSubMarker; markerToMove != NULL;) {
1269 Marker* nextMarkerToMove = OurStuff (markerToMove)->fNextSubMarker;
1270 OurStuff (markerToMove)->fNextSubMarker = NULL;
1271 OurStuff (markerToMove)->fParent = NULL;
1272 AddMarker1 (markerToMove, parent,
false);
1273 markerToMove = nextMarkerToMove;
1276 if (moveCount > 1) {
1277 PossiblyAddHackMarkers (parent);
1286 for (Marker* hmi = OurStuff (parent)->fFirstSubMarker; hmi != NULL;) {
1287 ChunkedArrayMarkerHook* hmiStuff = OurStuff (hmi);
1288 Marker* nexthmi = hmiStuff->fNextSubMarker;
1289 if (OurStuff (hmi)->fIsHackMarker) {
1290 if (AllHackMarkers (hmi)) {
1291 GetAMOH (hmi)->FreeHackTree (hmi);
1294 LoseIfUselessHackMarker (hmi);
1303 for (Marker* hmi = parent; OurStuff (hmi)->fIsHackMarker;) {
1304 Marker* nextUp = OurStuff (hmi)->fParent;
1305 if (AllHackMarkers (hmi)) {
1307 GetAMOH (hmi)->FreeHackTree (hmi);
1317Marker* ChunkedArrayTextStore::AddHackMarkerHelper_ (Marker* insideMarker,
size_t start,
size_t length)
1319 HackMarker* marker =
new HackMarker ();
1324 Assert (marker->fTextStoreHook == NULL);
1325 marker->fTextStoreHook =
new ChunkedArrayMarkerHook ();
1326 Assert (OurStuff (marker)->fParent == NULL);
1327 OurStuff (marker)->fParent = insideMarker;
1328 SetMarkerOwner_ (marker, OurStuff (insideMarker)->fOwner);
1329 SetMarkerStart_ (marker, start);
1330 SetMarkerLength_ (marker, length);
1331 OurStuff (insideMarker)->AddToChildList (marker);
1333 Assert (not OurStuff (marker)->fIsHackMarker);
1334 OurStuff (marker)->fIsHackMarker =
true;
1335#if qStroika_Frameworks_Led_KeepChunkedArrayStatistics
1336 ++GetAMOH (insideMarker)->fTotalHackMarkersAlloced;
1337 ++GetAMOH (insideMarker)->fTotalHackMarkersPresent;
1338 GetAMOH (insideMarker)->fPeakHackMarkersPresent =
1339 max (GetAMOH (insideMarker)->fPeakHackMarkersPresent, GetAMOH (insideMarker)->fTotalHackMarkersPresent);
1351void ChunkedArrayTextStore::LoseIfUselessHackMarker (Marker* potentiallyUselessHackMarker)
1354 Assert (OurStuff (potentiallyUselessHackMarker)->fIsHackMarker);
1356 Marker* firstChild = OurStuff (potentiallyUselessHackMarker)->fFirstSubMarker;
1358 bool truelyUseless = (firstChild == NULL) or (OurStuff (firstChild)->fNextSubMarker == NULL);
1366 if (firstChild != NULL and OurStuff (firstChild)->fNextSubMarker == NULL) {
1367 Assert (truelyUseless);
1368 Marker* goodParent = OurStuff (potentiallyUselessHackMarker)->fParent;
1369 Assert (OurStuff (firstChild)->fParent == potentiallyUselessHackMarker);
1370 OurStuff (firstChild)->fParent = goodParent;
1371 OurStuff (firstChild)->fNextSubMarker = OurStuff (goodParent)->fFirstSubMarker;
1372 OurStuff (goodParent)->fFirstSubMarker = firstChild;
1373 OurStuff (potentiallyUselessHackMarker)->fFirstSubMarker = NULL;
1377 if (truelyUseless) {
1378 GetAMOH (potentiallyUselessHackMarker)->FreeHackTree (potentiallyUselessHackMarker);
1382void ChunkedArrayTextStore::SetMarkerRange (Marker* marker,
size_t start,
size_t end)
noexcept
1385#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
1386 GetAMOH (marker)->ClearCache ();
1400 Assert (start >= 0);
1402 Assert (start <= end);
1405 size_t len = end - start;
1408 if (GetMarkerStart_ (marker) != start or GetMarkerLength_ (marker) != len) {
1414 Marker* parent = OurStuff (marker)->fParent;
1416 Assert (QUICK_Contains (*marker, *parent));
1417 if (Contains (start, end, *parent)) {
1420 for (Marker* mi = OurStuff (marker)->fFirstSubMarker; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1421 Assert (QUICK_Contains (*mi, *marker));
1425 SetMarkerStart_ (marker, start);
1426 SetMarkerLength_ (marker, len);
1432 Marker* prevMarker = NULL;
1433 for (Marker* mi = OurStuff (marker)->fFirstSubMarker; mi != NULL;) {
1434 Marker* nextMarker = OurStuff (mi)->fNextSubMarker;
1435 if (not QUICK_Contains (*mi, *marker)) {
1436 if (prevMarker == NULL) {
1437 Assert (OurStuff (marker)->fFirstSubMarker == mi);
1438 OurStuff (marker)->fFirstSubMarker = OurStuff (mi)->fNextSubMarker;
1441 Assert (OurStuff (prevMarker)->fNextSubMarker == mi);
1442 OurStuff (prevMarker)->fNextSubMarker = nextMarker;
1444 OurStuff (mi)->fNextSubMarker = NULL;
1445 OurStuff (mi)->fParent = NULL;
1446 AddMarker1 (mi, parent,
false);
1457 RemoveMarker (marker);
1458 AddMarker (marker, start, len, owner);
1463struct StackContext {
1464 const Marker* saved_belowHere;
1467void ChunkedArrayTextStore::CollectAllMarkersInRangeInto (
size_t from,
size_t to,
const MarkerOwner* owner, MarkerSink& output)
const
1470 Require (from <= to);
1479 if (owner == kAnyMarkerOwner) {
1480 for (vector<MarkerOwner*>::const_iterator i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1481 CollectAllMarkersInRangeInto_Helper_MO (from, to, *i, output);
1485#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
1486 ChunkedArrayMarkerOwnerHook* camoh = GetAMOH (owner);
1487 CollectLookupCacheElt* cacheItem = camoh->LookupElement (CollectLookupCacheElt::COMPARE_ITEM (from, to));
1488 if (cacheItem != NULL) {
1489 for (vector<Marker*>::const_iterator i = cacheItem->fMarkers.begin (); i != cacheItem->fMarkers.end (); ++i) {
1490 if (not OurStuff (*i)->fIsPreRemoved) {
1496 if (cacheItem == NULL and (to - from) <= 3) {
1497 cacheItem = camoh->AddNew (CollectLookupCacheElt::COMPARE_ITEM (from, to));
1498 cacheItem->fFrom = from;
1499 cacheItem->fTo = to;
1500 cacheItem->fMarkers.clear ();
1501 CollectAllMarkersInRangeInto_Helper_MO (from, to, owner, output, cacheItem);
1505 CollectAllMarkersInRangeInto_Helper_MO (from, to, owner, output);
1509void ChunkedArrayTextStore::CollectAllMarkersInRangeInto_Helper_MO (
size_t from,
size_t to,
const MarkerOwner* owner, MarkerSink& output
1510#
if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
1512 CollectLookupCacheElt* fillingCache
1516 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> (owner->fTextStoreHook);
1518 const Marker* belowHere = &camoh->fRootMarker;
1519 size_t stackDepth = 0;
1524 Marker* mi = OurStuff (belowHere)->fFirstSubMarker;
1525 ChunkedArrayMarkerHook* mio = mi == NULL ? NULL : OurStuff (mi);
1526 for (; mi != NULL; (mi = mio->fNextSubMarker), (mio = mi == NULL ? NULL : OurStuff (mi))) {
1529 Assert (mio == OurStuff (mi));
1530 Assert (QUICK_Overlap (mio, from, to) == QUICK_Overlap (*mi, from, to));
1531 if (QUICK_Overlap (mio, from, to)) {
1532 if (not mio->fIsHackMarker and not mio->fIsPreRemoved) {
1533#if qStroika_Frameworks_Led_UseLRUCacheForRecentlyLookedUpMarkers
1534 if (fillingCache != NULL) {
1535 fillingCache->fMarkers.push_back (mi);
1541 stack.GrowToSize (stackDepth + 1);
1542 stack[stackDepth].saved_belowHere = belowHere;
1543 stack[stackDepth].saved_mi = mi;
1548 Assert (stackDepth > 0);
1550 belowHere = stack[stackDepth].saved_belowHere;
1551 mi = stack[stackDepth].saved_mi;
1553 mio = OurStuff (mi);
1556 if (stackDepth != 0) {
1558 goto AfterCallPoint;
1562ChunkedArrayTextStore::ChunkAndOffset ChunkedArrayTextStore::FindChunkIndex_ (
size_t charPos)
const
1564 Assert (charPos >= 0);
1565 Assert (charPos <= GetEnd ());
1566 size_t totalChunks = fTextChunks.size ();
1567 size_t bytePosSoFar = 0;
1582 if (charPos >= fCachedChunkIndexesOffset) {
1583 startAt = fCachedChunkIndex;
1584 Assert (fCachedChunkIndexesOffset >= 0);
1585 bytePosSoFar = fCachedChunkIndexesOffset;
1587 for (
size_t i = startAt; i < totalChunks; ++i) {
1589 size_t curChunkSize = fTextChunks[i]->GetLength ();
1590 if (bytePosSoFar + curChunkSize > charPos) {
1591 Assert (charPos >= bytePosSoFar + 0);
1593 fCachedChunkIndex = i;
1594 fCachedChunkIndexesOffset = bytePosSoFar + 0;
1595 return (ChunkAndOffset (i, charPos - bytePosSoFar));
1597 bytePosSoFar += curChunkSize;
1599 return (ChunkAndOffset (totalChunks, 0));
1602void ChunkedArrayTextStore::AdjustMarkersForInsertAfter (
size_t after,
size_t howMany)
1604 for (
auto i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1605 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> ((*i)->fTextStoreHook);
1607 AdjustMarkersForInsertAfter1 (after, howMany, &camoh->fRootMarker);
1611void ChunkedArrayTextStore::AdjustMarkersForInsertAfter1 (
size_t after,
size_t howMany, Marker* startAt)
1616 size_t stackDepth = 0;
1627 size_t start = GetMarkerStart_ (startAt);
1628 size_t len = GetMarkerLength_ (startAt);
1629 size_t end = start + len;
1630 if (after < start) {
1631 SetMarkerStart_ (startAt, start + howMany);
1633 else if (after >= start and after < end) {
1634 SetMarkerLength_ (startAt, len + howMany);
1637 Assert (after >= end);
1638 if (stackDepth == 0) {
1642 goto AfterCallPoint;
1650 for (mi = OurStuff (startAt)->fFirstSubMarker; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1652 stack.GrowToSize (stackDepth + 1);
1653 stack[stackDepth] = mi;
1658 Assert (stackDepth > 0);
1660 mi = stack[stackDepth];
1662 if (stackDepth != 0) {
1664 goto AfterCallPoint;
1668void ChunkedArrayTextStore::AdjustMarkersForDeleteAfter (
size_t after,
size_t howMany)
1670 for (
auto i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1671 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> ((*i)->fTextStoreHook);
1673 AdjustMarkersForDeleteAfter1 (after, howMany, &camoh->fRootMarker);
1677void ChunkedArrayTextStore::AdjustMarkersForDeleteAfter1 (
size_t after,
size_t howMany, Marker* startAt)
1682 size_t stackDepth = 0;
1692 size_t start = GetMarkerStart_ (startAt);
1693 size_t len = GetMarkerLength_ (startAt);
1694 size_t end = start + len;
1695 if (after < start) {
1697 if (howMany + after <= start) {
1698 Assert (start >= howMany + 0);
1699 SetMarkerStart_ (startAt, start - howMany);
1702 Assert (howMany > (start - after));
1703 size_t deleteNCharsOffFront = howMany - (start - after);
1704 size_t moveFront = howMany - deleteNCharsOffFront;
1705 SetMarkerStart_ (startAt, start - moveFront);
1709 SetMarkerLength_ (startAt, (len > deleteNCharsOffFront) ? (len - deleteNCharsOffFront) : 0);
1712 else if (after >= start and after < end) {
1713 size_t newEnd = end;
1714 if (end - after < howMany) {
1720 Assert (newEnd >= start);
1721 size_t newLen = newEnd - start;
1722 SetMarkerLength_ (startAt, newLen);
1725 Assert (after >= end);
1726 if (stackDepth == 0) {
1730 goto AfterCallPoint;
1738 for (mi = OurStuff (startAt)->fFirstSubMarker; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1740 stack.GrowToSize (stackDepth + 1);
1741 stack[stackDepth] = mi;
1746 Assert (stackDepth > 0);
1748 mi = stack[stackDepth];
1751 if (stackDepth != 0) {
1753 goto AfterCallPoint;
1757bool ChunkedArrayTextStore::AllSubMarkersAreHackMarkerTrees (
const Marker* m)
1760 Assert (OurStuff (m)->fIsHackMarker);
1763 size_t stackDepth = 0;
1771 for (Marker* mi = OurStuff (m)->fFirstSubMarker; mi != NULL;) {
1772 ChunkedArrayMarkerHook* misStuff = OurStuff (mi);
1773 Assert (misStuff->fParent == m);
1774 if (not misStuff->fIsHackMarker) {
1777 mi = misStuff->fNextSubMarker;
1780 Marker* mi = OurStuff (m)->fFirstSubMarker;
1781 for (; mi != NULL; mi = OurStuff (mi)->fNextSubMarker) {
1782 Assert (OurStuff (mi)->fIsHackMarker);
1784 stack.GrowToSize (stackDepth + 1);
1785 stack[stackDepth] = mi;
1790 Assert (stackDepth > 0);
1792 mi = stack[stackDepth];
1795 if (stackDepth != 0) {
1797 goto AfterCallPoint;
1802#if qStroika_Foundation_Debug_AssertionsChecked
1803void ChunkedArrayTextStore::Invariant_ ()
const
1805 TextStore::Invariant_ ();
1806 for (
auto i = GetMarkerOwners ().begin (); i != GetMarkerOwners ().end (); ++i) {
1807 ChunkedArrayMarkerOwnerHook* camoh =
dynamic_cast<ChunkedArrayMarkerOwnerHook*
> ((*i)->fTextStoreHook);
1809 WalkSubTreeAndCheckInvariants (&camoh->fRootMarker);
1814#if qStroika_Foundation_Debug_AssertionsChecked
1815void ChunkedArrayTextStore::WalkSubTreeAndCheckInvariants (
const Marker* m)
const
1819 for (
const Marker* subMarker = OurStuff (m)->fFirstSubMarker; subMarker != NULL; subMarker = OurStuff (subMarker)->fNextSubMarker) {
1822 Assert (OurStuff (subMarker)->fParent == m);
1823 Assert (QUICK_Contains (*subMarker, *m));
1824 Assert (not OurStuff (subMarker)->fIsHackMarker or OurStuff (subMarker)->fFirstSubMarker != NULL);
1825 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...