1
// Scintilla source code edit control
2
/** @file Partitioning.h
3
** Data structure used to partition an interval. Used for holding line start/end positions.
5
// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
6
// The License.txt file describes the conditions under which this software may be distributed.
11
/// A split vector of integers with a method for adding a value to all elements
13
/// Used by the Partitioning class.
15
class SplitVectorWithRangeAdd : public SplitVector<int> {
17
SplitVectorWithRangeAdd(int growSize_) {
18
SetGrowSize(growSize_);
19
ReAllocate(growSize_);
21
~SplitVectorWithRangeAdd() {
23
void RangeAddDelta(int start, int end, int delta) {
24
// end is 1 past end, so end-start is number of elements to change
26
int rangeLength = end - start;
27
int range1Length = rangeLength;
28
int part1Left = part1Length - start;
29
if (range1Length > part1Left)
30
range1Length = part1Left;
31
while (i < range1Length) {
32
body[start++] += delta;
36
while (i < rangeLength) {
37
body[start++] += delta;
43
/// Divide an interval into multiple partitions.
44
/// Useful for breaking a document down into sections such as lines.
48
// To avoid calculating all the partition positions whenever any text is inserted
49
// there may be a step somewhere in the list.
52
SplitVectorWithRangeAdd *body;
55
void ApplyStep(int partitionUpTo) {
56
if (stepLength != 0) {
57
body->RangeAddDelta(stepPartition+1, partitionUpTo + 1, stepLength);
59
stepPartition = partitionUpTo;
60
if (stepPartition >= body->Length()-1) {
61
stepPartition = body->Length()-1;
67
void BackStep(int partitionDownTo) {
68
if (stepLength != 0) {
69
body->RangeAddDelta(partitionDownTo+1, stepPartition+1, -stepLength);
71
stepPartition = partitionDownTo;
74
void Allocate(int growSize) {
75
body = new SplitVectorWithRangeAdd(growSize);
78
body->Insert(0, 0); // This value stays 0 for ever
79
body->Insert(1, 0); // This is the end of the first partition and will be the start of the second
83
Partitioning(int growSize) {
92
int Partitions() const {
93
return body->Length()-1;
96
void InsertPartition(int partition, int pos) {
97
if (stepPartition < partition) {
100
body->Insert(partition, pos);
104
void SetPartitionStartPosition(int partition, int pos) {
105
ApplyStep(partition+1);
106
if ((partition < 0) || (partition > body->Length())) {
109
body->SetValueAt(partition, pos);
112
void InsertText(int partitionInsert, int delta) {
113
// Point all the partitions after the insertion point further along in the buffer
114
if (stepLength != 0) {
115
if (partitionInsert >= stepPartition) {
116
// Fill in up to the new insertion point
117
ApplyStep(partitionInsert);
119
} else if (partitionInsert >= (stepPartition - body->Length() / 10)) {
120
// Close to step but before so move step back
121
BackStep(partitionInsert);
124
ApplyStep(body->Length()-1);
125
stepPartition = partitionInsert;
129
stepPartition = partitionInsert;
134
void RemovePartition(int partition) {
135
if (partition > stepPartition) {
136
ApplyStep(partition);
141
body->Delete(partition);
144
int PositionFromPartition(int partition) const {
145
PLATFORM_ASSERT(partition >= 0);
146
PLATFORM_ASSERT(partition < body->Length());
147
if ((partition < 0) || (partition >= body->Length())) {
150
int pos = body->ValueAt(partition);
151
if (partition > stepPartition)
156
int PartitionFromPosition(int pos) const {
157
if (body->Length() <= 1)
159
if (pos >= (PositionFromPartition(body->Length()-1)))
160
return body->Length() - 1 - 1;
162
int upper = body->Length()-1;
164
int middle = (upper + lower + 1) / 2; // Round high
165
int posMiddle = body->ValueAt(middle);
166
if (middle > stepPartition)
167
posMiddle += stepLength;
168
if (pos < posMiddle) {
173
} while (lower < upper);
178
int growSize = body->GetGrowSize();