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();