1*8af74909SZhong Yang // Scintilla source code edit control 2*8af74909SZhong Yang /** @file SparseVector.h 3*8af74909SZhong Yang ** Hold data sparsely associated with elements in a range. 4*8af74909SZhong Yang **/ 5*8af74909SZhong Yang // Copyright 2016 by Neil Hodgson <[email protected]> 6*8af74909SZhong Yang // The License.txt file describes the conditions under which this software may be distributed. 7*8af74909SZhong Yang 8*8af74909SZhong Yang #ifndef SPARSEVECTOR_H 9*8af74909SZhong Yang #define SPARSEVECTOR_H 10*8af74909SZhong Yang 11*8af74909SZhong Yang namespace Scintilla { 12*8af74909SZhong Yang 13*8af74909SZhong Yang // SparseVector is similar to RunStyles but is more efficient for cases where values occur 14*8af74909SZhong Yang // for one position instead of over a range of positions. 15*8af74909SZhong Yang // There are always elements at the start and end, so the element type should have 16*8af74909SZhong Yang // a reasonable empty value that will cause no problems. 17*8af74909SZhong Yang // The element type should have a noexcept default constructor as that allows methods to 18*8af74909SZhong Yang // be noexcept. 19*8af74909SZhong Yang template <typename T> 20*8af74909SZhong Yang class SparseVector { 21*8af74909SZhong Yang private: 22*8af74909SZhong Yang std::unique_ptr<Partitioning<Sci::Position>> starts; 23*8af74909SZhong Yang std::unique_ptr<SplitVector<T>> values; 24*8af74909SZhong Yang T empty; // Return from ValueAt when no element at a position. ClearValue(Sci::Position partition)25*8af74909SZhong Yang void ClearValue(Sci::Position partition) noexcept { 26*8af74909SZhong Yang values->SetValueAt(partition, T()); 27*8af74909SZhong Yang } 28*8af74909SZhong Yang public: SparseVector()29*8af74909SZhong Yang SparseVector() : empty() { 30*8af74909SZhong Yang starts = std::make_unique<Partitioning<Sci::Position>>(8); 31*8af74909SZhong Yang values = std::make_unique<SplitVector<T>>(); 32*8af74909SZhong Yang values->InsertEmpty(0, 2); 33*8af74909SZhong Yang } 34*8af74909SZhong Yang // Deleted so SparseVector objects can not be copied. 35*8af74909SZhong Yang SparseVector(const SparseVector &) = delete; 36*8af74909SZhong Yang SparseVector(SparseVector &&) = delete; 37*8af74909SZhong Yang void operator=(const SparseVector &) = delete; 38*8af74909SZhong Yang void operator=(SparseVector &&) = delete; ~SparseVector()39*8af74909SZhong Yang ~SparseVector() { 40*8af74909SZhong Yang starts.reset(); 41*8af74909SZhong Yang // starts dead here but not used by ClearValue. 42*8af74909SZhong Yang for (Sci::Position part = 0; part < values->Length(); part++) { 43*8af74909SZhong Yang ClearValue(part); 44*8af74909SZhong Yang } 45*8af74909SZhong Yang values.reset(); 46*8af74909SZhong Yang } Length()47*8af74909SZhong Yang Sci::Position Length() const noexcept { 48*8af74909SZhong Yang return starts->Length(); 49*8af74909SZhong Yang } Elements()50*8af74909SZhong Yang Sci::Position Elements() const noexcept { 51*8af74909SZhong Yang return starts->Partitions(); 52*8af74909SZhong Yang } PositionOfElement(Sci::Position element)53*8af74909SZhong Yang Sci::Position PositionOfElement(Sci::Position element) const noexcept { 54*8af74909SZhong Yang return starts->PositionFromPartition(element); 55*8af74909SZhong Yang } ElementFromPosition(Sci::Position position)56*8af74909SZhong Yang Sci::Position ElementFromPosition(Sci::Position position) const noexcept { 57*8af74909SZhong Yang if (position < Length()) { 58*8af74909SZhong Yang return starts->PartitionFromPosition(position); 59*8af74909SZhong Yang } else { 60*8af74909SZhong Yang return starts->Partitions(); 61*8af74909SZhong Yang } 62*8af74909SZhong Yang } ValueAt(Sci::Position position)63*8af74909SZhong Yang const T& ValueAt(Sci::Position position) const noexcept { 64*8af74909SZhong Yang assert(position <= Length()); 65*8af74909SZhong Yang const Sci::Position partition = ElementFromPosition(position); 66*8af74909SZhong Yang const Sci::Position startPartition = starts->PositionFromPartition(partition); 67*8af74909SZhong Yang if (startPartition == position) { 68*8af74909SZhong Yang return values->ValueAt(partition); 69*8af74909SZhong Yang } else { 70*8af74909SZhong Yang return empty; 71*8af74909SZhong Yang } 72*8af74909SZhong Yang } 73*8af74909SZhong Yang template <typename ParamType> SetValueAt(Sci::Position position,ParamType && value)74*8af74909SZhong Yang void SetValueAt(Sci::Position position, ParamType &&value) { 75*8af74909SZhong Yang assert(position <= Length()); 76*8af74909SZhong Yang const Sci::Position partition = ElementFromPosition(position); 77*8af74909SZhong Yang const Sci::Position startPartition = starts->PositionFromPartition(partition); 78*8af74909SZhong Yang if (value == T()) { 79*8af74909SZhong Yang // Setting the empty value is equivalent to deleting the position 80*8af74909SZhong Yang if (position == 0) { 81*8af74909SZhong Yang ClearValue(partition); 82*8af74909SZhong Yang } else if (position == startPartition) { 83*8af74909SZhong Yang // Currently an element at this position, so remove 84*8af74909SZhong Yang ClearValue(partition); 85*8af74909SZhong Yang starts->RemovePartition(partition); 86*8af74909SZhong Yang values->Delete(partition); 87*8af74909SZhong Yang } 88*8af74909SZhong Yang // Else element remains empty 89*8af74909SZhong Yang } else { 90*8af74909SZhong Yang if (position == startPartition) { 91*8af74909SZhong Yang // Already a value at this position, so replace 92*8af74909SZhong Yang ClearValue(partition); 93*8af74909SZhong Yang values->SetValueAt(partition, std::forward<ParamType>(value)); 94*8af74909SZhong Yang } else { 95*8af74909SZhong Yang // Insert a new element 96*8af74909SZhong Yang starts->InsertPartition(partition + 1, position); 97*8af74909SZhong Yang values->Insert(partition + 1, std::forward<ParamType>(value)); 98*8af74909SZhong Yang } 99*8af74909SZhong Yang } 100*8af74909SZhong Yang } InsertSpace(Sci::Position position,Sci::Position insertLength)101*8af74909SZhong Yang void InsertSpace(Sci::Position position, Sci::Position insertLength) { 102*8af74909SZhong Yang assert(position <= Length()); 103*8af74909SZhong Yang const Sci::Position partition = starts->PartitionFromPosition(position); 104*8af74909SZhong Yang const Sci::Position startPartition = starts->PositionFromPartition(partition); 105*8af74909SZhong Yang if (startPartition == position) { 106*8af74909SZhong Yang const bool positionOccupied = values->ValueAt(partition) != T(); 107*8af74909SZhong Yang // Inserting at start of run so make previous longer 108*8af74909SZhong Yang if (partition == 0) { 109*8af74909SZhong Yang // Inserting at start of document so ensure start empty 110*8af74909SZhong Yang if (positionOccupied) { 111*8af74909SZhong Yang starts->InsertPartition(1, 0); 112*8af74909SZhong Yang values->InsertEmpty(0, 1); 113*8af74909SZhong Yang } 114*8af74909SZhong Yang starts->InsertText(partition, insertLength); 115*8af74909SZhong Yang } else { 116*8af74909SZhong Yang if (positionOccupied) { 117*8af74909SZhong Yang starts->InsertText(partition - 1, insertLength); 118*8af74909SZhong Yang } else { 119*8af74909SZhong Yang // Insert at end of run so do not extend style 120*8af74909SZhong Yang starts->InsertText(partition, insertLength); 121*8af74909SZhong Yang } 122*8af74909SZhong Yang } 123*8af74909SZhong Yang } else { 124*8af74909SZhong Yang starts->InsertText(partition, insertLength); 125*8af74909SZhong Yang } 126*8af74909SZhong Yang } DeletePosition(Sci::Position position)127*8af74909SZhong Yang void DeletePosition(Sci::Position position) { 128*8af74909SZhong Yang assert(position < Length()); 129*8af74909SZhong Yang Sci::Position partition = starts->PartitionFromPosition(position); 130*8af74909SZhong Yang const Sci::Position startPartition = starts->PositionFromPartition(partition); 131*8af74909SZhong Yang if (startPartition == position) { 132*8af74909SZhong Yang if (partition == 0) { 133*8af74909SZhong Yang ClearValue(0); 134*8af74909SZhong Yang if (starts->PositionFromPartition(1) == 1) { 135*8af74909SZhong Yang // Removing all space of first partition, so remove next partition 136*8af74909SZhong Yang // and move value if not last 137*8af74909SZhong Yang if (Elements() > 1) { 138*8af74909SZhong Yang starts->RemovePartition(partition + 1); 139*8af74909SZhong Yang values->Delete(partition); 140*8af74909SZhong Yang } 141*8af74909SZhong Yang } 142*8af74909SZhong Yang } else if (partition == starts->Partitions()) { 143*8af74909SZhong Yang // This should not be possible 144*8af74909SZhong Yang ClearValue(partition); 145*8af74909SZhong Yang throw std::runtime_error("SparseVector: deleting end partition."); 146*8af74909SZhong Yang } else { 147*8af74909SZhong Yang ClearValue(partition); 148*8af74909SZhong Yang starts->RemovePartition(partition); 149*8af74909SZhong Yang values->Delete(partition); 150*8af74909SZhong Yang // Its the previous partition now that gets smaller 151*8af74909SZhong Yang partition--; 152*8af74909SZhong Yang } 153*8af74909SZhong Yang } 154*8af74909SZhong Yang starts->InsertText(partition, -1); 155*8af74909SZhong Yang Check(); 156*8af74909SZhong Yang } DeleteRange(Sci::Position position,Sci::Position deleteLength)157*8af74909SZhong Yang void DeleteRange(Sci::Position position, Sci::Position deleteLength) { 158*8af74909SZhong Yang // For now, delete elements in range - may want to leave value at start 159*8af74909SZhong Yang // or combine onto position. 160*8af74909SZhong Yang if (position > Length() || (deleteLength == 0)) { 161*8af74909SZhong Yang return; 162*8af74909SZhong Yang } 163*8af74909SZhong Yang const Sci::Position positionEnd = position + deleteLength; 164*8af74909SZhong Yang assert(positionEnd <= Length()); 165*8af74909SZhong Yang if (position == 0) { 166*8af74909SZhong Yang // Remove all partitions in range, moving values to start 167*8af74909SZhong Yang while ((Elements() > 1) && (starts->PositionFromPartition(1) <= deleteLength)) { 168*8af74909SZhong Yang starts->RemovePartition(1); 169*8af74909SZhong Yang values->Delete(0); 170*8af74909SZhong Yang } 171*8af74909SZhong Yang starts->InsertText(0, -deleteLength); 172*8af74909SZhong Yang if (Length() == 0) { 173*8af74909SZhong Yang ClearValue(0); 174*8af74909SZhong Yang } 175*8af74909SZhong Yang } else { 176*8af74909SZhong Yang const Sci::Position partition = starts->PartitionFromPosition(position); 177*8af74909SZhong Yang const bool atPartitionStart = position == starts->PositionFromPartition(partition); 178*8af74909SZhong Yang const Sci::Position partitionDelete = partition + (atPartitionStart ? 0 : 1); 179*8af74909SZhong Yang assert(partitionDelete > 0); 180*8af74909SZhong Yang for (;;) { 181*8af74909SZhong Yang const Sci::Position positionAtIndex = starts->PositionFromPartition(partitionDelete); 182*8af74909SZhong Yang assert(position <= positionAtIndex); 183*8af74909SZhong Yang if (positionAtIndex >= positionEnd) { 184*8af74909SZhong Yang break; 185*8af74909SZhong Yang } 186*8af74909SZhong Yang assert(partitionDelete <= Elements()); 187*8af74909SZhong Yang starts->RemovePartition(partitionDelete); 188*8af74909SZhong Yang values->Delete(partitionDelete); 189*8af74909SZhong Yang } 190*8af74909SZhong Yang starts->InsertText(partition - (atPartitionStart ? 1 : 0), -deleteLength); 191*8af74909SZhong Yang } 192*8af74909SZhong Yang Check(); 193*8af74909SZhong Yang } IndexAfter(Sci::Position position)194*8af74909SZhong Yang Sci::Position IndexAfter(Sci::Position position) const noexcept { 195*8af74909SZhong Yang assert(position < Length()); 196*8af74909SZhong Yang if (position < 0) 197*8af74909SZhong Yang return 0; 198*8af74909SZhong Yang const Sci::Position partition = starts->PartitionFromPosition(position); 199*8af74909SZhong Yang return partition + 1; 200*8af74909SZhong Yang } Check()201*8af74909SZhong Yang void Check() const { 202*8af74909SZhong Yang #ifdef CHECK_CORRECTNESS 203*8af74909SZhong Yang starts->Check(); 204*8af74909SZhong Yang if (starts->Partitions() != values->Length() - 1) { 205*8af74909SZhong Yang throw std::runtime_error("SparseVector: Partitions and values different lengths."); 206*8af74909SZhong Yang } 207*8af74909SZhong Yang #endif 208*8af74909SZhong Yang } 209*8af74909SZhong Yang }; 210*8af74909SZhong Yang 211*8af74909SZhong Yang } 212*8af74909SZhong Yang 213*8af74909SZhong Yang #endif 214