-
Notifications
You must be signed in to change notification settings - Fork 16
Use an append-only buffer for the additions in the piecetable. #422
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9a7f789
6a92e49
bb157cb
145f766
099eb6e
7890889
012e8cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,86 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * Copyright (C) 2025 Gluon | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * This program is free software: you can redistribute it and/or modify | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * it under the terms of the GNU General Public License as published by | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * the Free Software Foundation, either version 3 of the License, or | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * (at your option) any later version. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * This program is distributed in the hope that it will be useful, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * GNU General Public License for more details. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * You should have received a copy of the GNU General Public License | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| package com.gluonhq.richtextarea.model; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.Arrays; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||
| * Append-only buffer used as the PieceTable Addition Buffer | ||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public class AppendOnlyUnitBuffer extends UnitBuffer { | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| int[] unitLengths = new int[4096]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public void append(List<Unit> units) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ensureCapacity(unitList.size() + units.size()); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| for (Unit u: units) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| doAppend(u); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public void append(Unit unit) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ensureCapacity(unitList.size() + 1); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| doAppend(unit); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| private void doAppend(Unit unit) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| int idx = unitList.size(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| int oldLength = idx == 0 ? 0 : unitLengths[idx-1]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| unitLengths[idx]= oldLength + unit.length(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| unitList.add(unit); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| dirty = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public void insert(Unit unit, int position) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new UnsupportedOperationException("Do not insert in an append-only buffer"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public void remove(int start, int end) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new UnsupportedOperationException("Do not remove from an append-only buffer"); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| @Override | ||||||||||||||||||||||||||||||||||||||||||||||||||
| public Unit getUnitWithRange(int start, int end) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (start < 0 || unitList.isEmpty()) return new TextUnit(""); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| int index = Arrays.binarySearch(unitLengths, 0, unitList.size(), start); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (index >=0) { // exact start at index | ||||||||||||||||||||||||||||||||||||||||||||||||||
| index = index+1; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { // no exact item found | ||||||||||||||||||||||||||||||||||||||||||||||||||
| index = -(index) -1; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return unitList.get(index); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+64
to
+71
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (start < 0 || unitList.isEmpty()) return new TextUnit(""); | |
| int index = Arrays.binarySearch(unitLengths, 0, unitList.size(), start); | |
| if (index >=0) { // exact start at index | |
| index = index+1; | |
| } else { // no exact item found | |
| index = -(index) -1; | |
| } | |
| return unitList.get(index); | |
| if (start < 0 || end <= start || unitList.isEmpty()) return new TextUnit(""); | |
| int index = Arrays.binarySearch(unitLengths, 0, unitList.size(), start); | |
| if (index >= 0) { // exact start at index | |
| index = index + 1; | |
| } else { // no exact item found | |
| index = -(index) - 1; | |
| } | |
| // Now, index is the first unit whose end offset is > start | |
| if (index >= unitList.size()) return new TextUnit(""); | |
| int unitStart = (index == 0) ? 0 : unitLengths[index - 1]; | |
| int unitEnd = unitLengths[index]; | |
| if (start >= unitStart && end <= unitEnd) { | |
| return unitList.get(index); | |
| } else { | |
| return new TextUnit(""); | |
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /* | ||
| * Copyright (C) 2025 Gluon | ||
| * | ||
| * This program is free software: you can redistribute it and/or modify | ||
| * it under the terms of the GNU General Public License as published by | ||
| * the Free Software Foundation, either version 3 of the License, or | ||
| * (at your option) any later version. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| * GNU General Public License for more details. | ||
| * | ||
| * You should have received a copy of the GNU General Public License | ||
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| * DISCLAIMED. IN NO EVENT SHALL GLUON BE LIABLE FOR ANY | ||
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| */ | ||
| package com.gluonhq.richtextarea.model; | ||
|
|
||
| import org.junit.jupiter.api.Assertions; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| /** | ||
| * | ||
| * @author johan | ||
| */ | ||
| public class AppendOnlyUnitBufferTests { | ||
|
|
||
| @Test | ||
| public void testCapacity() { | ||
| final AppendOnlyUnitBuffer additionBuffer = new AppendOnlyUnitBuffer(); | ||
| int len = additionBuffer.unitLengths.length; | ||
| Assertions.assertTrue(len > 0); | ||
| int belowMax = (int)(len*.9); | ||
| for (int i = 0; i < belowMax; i++) { | ||
| TextUnit tu = new TextUnit("a"); | ||
| additionBuffer.append(tu); | ||
| } | ||
| int len2 = additionBuffer.unitLengths.length; | ||
| Assertions.assertEquals(len, len2); | ||
| int aboveMax = (int)(len*1.1); | ||
| for (int i = belowMax; i < aboveMax; i++) { | ||
| TextUnit tu = new TextUnit("a"); | ||
| additionBuffer.append(tu); | ||
| } | ||
| int len3 = additionBuffer.unitLengths.length; | ||
| Assertions.assertNotEquals(len, len3); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing class-level documentation. The comment is empty and should describe the purpose of this class, particularly explaining that it uses a cumulative length array for optimized lookups and any limitations (such as the hard limit on 4K elements mentioned in the PR description).