1*8af74909SZhong Yang // Scintilla source code edit control 2*8af74909SZhong Yang /** @file Partitioning.h 3*8af74909SZhong Yang ** Data structure used to partition an interval. Used for holding line start/end positions. 4*8af74909SZhong Yang **/ 5*8af74909SZhong Yang // Copyright 1998-2007 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 PARTITIONING_H 9*8af74909SZhong Yang #define PARTITIONING_H 10*8af74909SZhong Yang 11*8af74909SZhong Yang namespace Scintilla { 12*8af74909SZhong Yang 13*8af74909SZhong Yang /// A split vector of integers with a method for adding a value to all elements 14*8af74909SZhong Yang /// in a range. 15*8af74909SZhong Yang /// Used by the Partitioning class. 16*8af74909SZhong Yang 17*8af74909SZhong Yang template <typename T> 18*8af74909SZhong Yang class SplitVectorWithRangeAdd : public SplitVector<T> { 19*8af74909SZhong Yang public: SplitVectorWithRangeAdd(ptrdiff_t growSize_)20*8af74909SZhong Yang explicit SplitVectorWithRangeAdd(ptrdiff_t growSize_) { 21*8af74909SZhong Yang this->SetGrowSize(growSize_); 22*8af74909SZhong Yang this->ReAllocate(growSize_); 23*8af74909SZhong Yang } 24*8af74909SZhong Yang // Deleted so SplitVectorWithRangeAdd objects can not be copied. 25*8af74909SZhong Yang SplitVectorWithRangeAdd(const SplitVectorWithRangeAdd &) = delete; 26*8af74909SZhong Yang SplitVectorWithRangeAdd(SplitVectorWithRangeAdd &&) = delete; 27*8af74909SZhong Yang void operator=(const SplitVectorWithRangeAdd &) = delete; 28*8af74909SZhong Yang void operator=(SplitVectorWithRangeAdd &&) = delete; ~SplitVectorWithRangeAdd()29*8af74909SZhong Yang ~SplitVectorWithRangeAdd() { 30*8af74909SZhong Yang } RangeAddDelta(ptrdiff_t start,ptrdiff_t end,T delta)31*8af74909SZhong Yang void RangeAddDelta(ptrdiff_t start, ptrdiff_t end, T delta) noexcept { 32*8af74909SZhong Yang // end is 1 past end, so end-start is number of elements to change 33*8af74909SZhong Yang ptrdiff_t i = 0; 34*8af74909SZhong Yang const ptrdiff_t rangeLength = end - start; 35*8af74909SZhong Yang ptrdiff_t range1Length = rangeLength; 36*8af74909SZhong Yang const ptrdiff_t part1Left = this->part1Length - start; 37*8af74909SZhong Yang if (range1Length > part1Left) 38*8af74909SZhong Yang range1Length = part1Left; 39*8af74909SZhong Yang while (i < range1Length) { 40*8af74909SZhong Yang this->body[start++] += delta; 41*8af74909SZhong Yang i++; 42*8af74909SZhong Yang } 43*8af74909SZhong Yang start += this->gapLength; 44*8af74909SZhong Yang while (i < rangeLength) { 45*8af74909SZhong Yang this->body[start++] += delta; 46*8af74909SZhong Yang i++; 47*8af74909SZhong Yang } 48*8af74909SZhong Yang } 49*8af74909SZhong Yang }; 50*8af74909SZhong Yang 51*8af74909SZhong Yang /// Divide an interval into multiple partitions. 52*8af74909SZhong Yang /// Useful for breaking a document down into sections such as lines. 53*8af74909SZhong Yang /// A 0 length interval has a single 0 length partition, numbered 0 54*8af74909SZhong Yang /// If interval not 0 length then each partition non-zero length 55*8af74909SZhong Yang /// When needed, positions after the interval are considered part of the last partition 56*8af74909SZhong Yang /// but the end of the last partition can be found with PositionFromPartition(last+1). 57*8af74909SZhong Yang 58*8af74909SZhong Yang template <typename T> 59*8af74909SZhong Yang class Partitioning { 60*8af74909SZhong Yang private: 61*8af74909SZhong Yang // To avoid calculating all the partition positions whenever any text is inserted 62*8af74909SZhong Yang // there may be a step somewhere in the list. 63*8af74909SZhong Yang T stepPartition; 64*8af74909SZhong Yang T stepLength; 65*8af74909SZhong Yang std::unique_ptr<SplitVectorWithRangeAdd<T>> body; 66*8af74909SZhong Yang 67*8af74909SZhong Yang // Move step forward ApplyStep(T partitionUpTo)68*8af74909SZhong Yang void ApplyStep(T partitionUpTo) noexcept { 69*8af74909SZhong Yang if (stepLength != 0) { 70*8af74909SZhong Yang body->RangeAddDelta(stepPartition+1, partitionUpTo + 1, stepLength); 71*8af74909SZhong Yang } 72*8af74909SZhong Yang stepPartition = partitionUpTo; 73*8af74909SZhong Yang if (stepPartition >= body->Length()-1) { 74*8af74909SZhong Yang stepPartition = Partitions(); 75*8af74909SZhong Yang stepLength = 0; 76*8af74909SZhong Yang } 77*8af74909SZhong Yang } 78*8af74909SZhong Yang 79*8af74909SZhong Yang // Move step backward BackStep(T partitionDownTo)80*8af74909SZhong Yang void BackStep(T partitionDownTo) noexcept { 81*8af74909SZhong Yang if (stepLength != 0) { 82*8af74909SZhong Yang body->RangeAddDelta(partitionDownTo+1, stepPartition+1, -stepLength); 83*8af74909SZhong Yang } 84*8af74909SZhong Yang stepPartition = partitionDownTo; 85*8af74909SZhong Yang } 86*8af74909SZhong Yang Allocate(ptrdiff_t growSize)87*8af74909SZhong Yang void Allocate(ptrdiff_t growSize) { 88*8af74909SZhong Yang body = std::make_unique<SplitVectorWithRangeAdd<T>>(growSize); 89*8af74909SZhong Yang stepPartition = 0; 90*8af74909SZhong Yang stepLength = 0; 91*8af74909SZhong Yang body->Insert(0, 0); // This value stays 0 for ever 92*8af74909SZhong Yang body->Insert(1, 0); // This is the end of the first partition and will be the start of the second 93*8af74909SZhong Yang } 94*8af74909SZhong Yang 95*8af74909SZhong Yang public: Partitioning(int growSize)96*8af74909SZhong Yang explicit Partitioning(int growSize) : stepPartition(0), stepLength(0) { 97*8af74909SZhong Yang Allocate(growSize); 98*8af74909SZhong Yang } 99*8af74909SZhong Yang 100*8af74909SZhong Yang // Deleted so Partitioning objects can not be copied. 101*8af74909SZhong Yang Partitioning(const Partitioning &) = delete; 102*8af74909SZhong Yang Partitioning(Partitioning &&) = delete; 103*8af74909SZhong Yang void operator=(const Partitioning &) = delete; 104*8af74909SZhong Yang void operator=(Partitioning &&) = delete; 105*8af74909SZhong Yang ~Partitioning()106*8af74909SZhong Yang ~Partitioning() { 107*8af74909SZhong Yang } 108*8af74909SZhong Yang Partitions()109*8af74909SZhong Yang T Partitions() const noexcept { 110*8af74909SZhong Yang return static_cast<T>(body->Length())-1; 111*8af74909SZhong Yang } 112*8af74909SZhong Yang Length()113*8af74909SZhong Yang T Length() const noexcept { 114*8af74909SZhong Yang return PositionFromPartition(Partitions()); 115*8af74909SZhong Yang } 116*8af74909SZhong Yang InsertPartition(T partition,T pos)117*8af74909SZhong Yang void InsertPartition(T partition, T pos) { 118*8af74909SZhong Yang if (stepPartition < partition) { 119*8af74909SZhong Yang ApplyStep(partition); 120*8af74909SZhong Yang } 121*8af74909SZhong Yang body->Insert(partition, pos); 122*8af74909SZhong Yang stepPartition++; 123*8af74909SZhong Yang } 124*8af74909SZhong Yang InsertPartitions(T partition,const T * positions,size_t length)125*8af74909SZhong Yang void InsertPartitions(T partition, const T *positions, size_t length) { 126*8af74909SZhong Yang if (stepPartition < partition) { 127*8af74909SZhong Yang ApplyStep(partition); 128*8af74909SZhong Yang } 129*8af74909SZhong Yang body->InsertFromArray(partition, positions, 0, length); 130*8af74909SZhong Yang stepPartition += static_cast<T>(length); 131*8af74909SZhong Yang } 132*8af74909SZhong Yang InsertPartitionsWithCast(T partition,const ptrdiff_t * positions,size_t length)133*8af74909SZhong Yang void InsertPartitionsWithCast(T partition, const ptrdiff_t *positions, size_t length) { 134*8af74909SZhong Yang // Used for 64-bit builds when T is 32-bits 135*8af74909SZhong Yang if (stepPartition < partition) { 136*8af74909SZhong Yang ApplyStep(partition); 137*8af74909SZhong Yang } 138*8af74909SZhong Yang T *pInsertion = body->InsertEmpty(partition, length); 139*8af74909SZhong Yang for (size_t i = 0; i < length; i++) { 140*8af74909SZhong Yang pInsertion[i] = static_cast<T>(positions[i]); 141*8af74909SZhong Yang } 142*8af74909SZhong Yang stepPartition += static_cast<T>(length); 143*8af74909SZhong Yang } 144*8af74909SZhong Yang SetPartitionStartPosition(T partition,T pos)145*8af74909SZhong Yang void SetPartitionStartPosition(T partition, T pos) noexcept { 146*8af74909SZhong Yang ApplyStep(partition+1); 147*8af74909SZhong Yang if ((partition < 0) || (partition > body->Length())) { 148*8af74909SZhong Yang return; 149*8af74909SZhong Yang } 150*8af74909SZhong Yang body->SetValueAt(partition, pos); 151*8af74909SZhong Yang } 152*8af74909SZhong Yang InsertText(T partitionInsert,T delta)153*8af74909SZhong Yang void InsertText(T partitionInsert, T delta) noexcept { 154*8af74909SZhong Yang // Point all the partitions after the insertion point further along in the buffer 155*8af74909SZhong Yang if (stepLength != 0) { 156*8af74909SZhong Yang if (partitionInsert >= stepPartition) { 157*8af74909SZhong Yang // Fill in up to the new insertion point 158*8af74909SZhong Yang ApplyStep(partitionInsert); 159*8af74909SZhong Yang stepLength += delta; 160*8af74909SZhong Yang } else if (partitionInsert >= (stepPartition - body->Length() / 10)) { 161*8af74909SZhong Yang // Close to step but before so move step back 162*8af74909SZhong Yang BackStep(partitionInsert); 163*8af74909SZhong Yang stepLength += delta; 164*8af74909SZhong Yang } else { 165*8af74909SZhong Yang ApplyStep(Partitions()); 166*8af74909SZhong Yang stepPartition = partitionInsert; 167*8af74909SZhong Yang stepLength = delta; 168*8af74909SZhong Yang } 169*8af74909SZhong Yang } else { 170*8af74909SZhong Yang stepPartition = partitionInsert; 171*8af74909SZhong Yang stepLength = delta; 172*8af74909SZhong Yang } 173*8af74909SZhong Yang } 174*8af74909SZhong Yang RemovePartition(T partition)175*8af74909SZhong Yang void RemovePartition(T partition) { 176*8af74909SZhong Yang if (partition > stepPartition) { 177*8af74909SZhong Yang ApplyStep(partition); 178*8af74909SZhong Yang stepPartition--; 179*8af74909SZhong Yang } else { 180*8af74909SZhong Yang stepPartition--; 181*8af74909SZhong Yang } 182*8af74909SZhong Yang body->Delete(partition); 183*8af74909SZhong Yang } 184*8af74909SZhong Yang PositionFromPartition(T partition)185*8af74909SZhong Yang T PositionFromPartition(T partition) const noexcept { 186*8af74909SZhong Yang PLATFORM_ASSERT(partition >= 0); 187*8af74909SZhong Yang PLATFORM_ASSERT(partition < body->Length()); 188*8af74909SZhong Yang const ptrdiff_t lengthBody = body->Length(); 189*8af74909SZhong Yang if ((partition < 0) || (partition >= lengthBody)) { 190*8af74909SZhong Yang return 0; 191*8af74909SZhong Yang } 192*8af74909SZhong Yang T pos = body->ValueAt(partition); 193*8af74909SZhong Yang if (partition > stepPartition) 194*8af74909SZhong Yang pos += stepLength; 195*8af74909SZhong Yang return pos; 196*8af74909SZhong Yang } 197*8af74909SZhong Yang 198*8af74909SZhong Yang /// Return value in range [0 .. Partitions() - 1] even for arguments outside interval PartitionFromPosition(T pos)199*8af74909SZhong Yang T PartitionFromPosition(T pos) const noexcept { 200*8af74909SZhong Yang if (body->Length() <= 1) 201*8af74909SZhong Yang return 0; 202*8af74909SZhong Yang if (pos >= (PositionFromPartition(Partitions()))) 203*8af74909SZhong Yang return Partitions() - 1; 204*8af74909SZhong Yang T lower = 0; 205*8af74909SZhong Yang T upper = Partitions(); 206*8af74909SZhong Yang do { 207*8af74909SZhong Yang const T middle = (upper + lower + 1) / 2; // Round high 208*8af74909SZhong Yang T posMiddle = body->ValueAt(middle); 209*8af74909SZhong Yang if (middle > stepPartition) 210*8af74909SZhong Yang posMiddle += stepLength; 211*8af74909SZhong Yang if (pos < posMiddle) { 212*8af74909SZhong Yang upper = middle - 1; 213*8af74909SZhong Yang } else { 214*8af74909SZhong Yang lower = middle; 215*8af74909SZhong Yang } 216*8af74909SZhong Yang } while (lower < upper); 217*8af74909SZhong Yang return lower; 218*8af74909SZhong Yang } 219*8af74909SZhong Yang DeleteAll()220*8af74909SZhong Yang void DeleteAll() { 221*8af74909SZhong Yang Allocate(body->GetGrowSize()); 222*8af74909SZhong Yang } 223*8af74909SZhong Yang Check()224*8af74909SZhong Yang void Check() const { 225*8af74909SZhong Yang #ifdef CHECK_CORRECTNESS 226*8af74909SZhong Yang if (Length() < 0) { 227*8af74909SZhong Yang throw std::runtime_error("Partitioning: Length can not be negative."); 228*8af74909SZhong Yang } 229*8af74909SZhong Yang if (Partitions() < 1) { 230*8af74909SZhong Yang throw std::runtime_error("Partitioning: Must always have 1 or more partitions."); 231*8af74909SZhong Yang } 232*8af74909SZhong Yang if (Length() == 0) { 233*8af74909SZhong Yang if ((PositionFromPartition(0) != 0) || (PositionFromPartition(1) != 0)) { 234*8af74909SZhong Yang throw std::runtime_error("Partitioning: Invalid empty partitioning."); 235*8af74909SZhong Yang } 236*8af74909SZhong Yang } else { 237*8af74909SZhong Yang // Positions should be a strictly ascending sequence 238*8af74909SZhong Yang for (T i = 0; i < Partitions(); i++) { 239*8af74909SZhong Yang const T pos = PositionFromPartition(i); 240*8af74909SZhong Yang const T posNext = PositionFromPartition(i+1); 241*8af74909SZhong Yang if (pos > posNext) { 242*8af74909SZhong Yang throw std::runtime_error("Partitioning: Negative partition."); 243*8af74909SZhong Yang } else if (pos == posNext) { 244*8af74909SZhong Yang throw std::runtime_error("Partitioning: Empty partition."); 245*8af74909SZhong Yang } 246*8af74909SZhong Yang } 247*8af74909SZhong Yang } 248*8af74909SZhong Yang #endif 249*8af74909SZhong Yang } 250*8af74909SZhong Yang 251*8af74909SZhong Yang }; 252*8af74909SZhong Yang 253*8af74909SZhong Yang 254*8af74909SZhong Yang } 255*8af74909SZhong Yang 256*8af74909SZhong Yang #endif 257