diff --git a/agrona/src/main/java/org/agrona/collections/IntArrayList.java b/agrona/src/main/java/org/agrona/collections/IntArrayList.java index 3a5ac0a7b..f1a2a08cc 100644 --- a/agrona/src/main/java/org/agrona/collections/IntArrayList.java +++ b/agrona/src/main/java/org/agrona/collections/IntArrayList.java @@ -319,6 +319,36 @@ public Integer remove( return value; } + /** + * Removes element at index, but instead of copying all elements to the + * left, moves into the same slot the last element. This avoids the copy + * costs, but spoils the list order. If index is the last element it is just + * removed. + * + * @param index + * of the element to be removed. + * @return the existing value at this index. + * @throws IndexOutOfBoundsException + * if index is out of bounds. + */ + public int fastUnorderedRemove( + @DoNotSub final int index) + { + checkIndex(index); + + final int value = elements[index]; + + @DoNotSub final int moveCount = size - index - 1; + if (moveCount > 0) + { + elements[index] = elements[size - 1]; + } + + size--; + + return value; + } + /** * Remove the first instance of a value if found in the list. * diff --git a/agrona/src/test/java/org/agrona/collections/IntArrayListTest.java b/agrona/src/test/java/org/agrona/collections/IntArrayListTest.java index 9dd0574c5..909d722a1 100644 --- a/agrona/src/test/java/org/agrona/collections/IntArrayListTest.java +++ b/agrona/src/test/java/org/agrona/collections/IntArrayListTest.java @@ -138,6 +138,18 @@ public void shouldRemoveAtIndex() assertThat(list.getInt(10), is(11)); } + @Test + public void shouldFastRemoveUnorderedAtIndex() + { + final int count = 20; + IntStream.range(0, count).forEachOrdered(list::addInt); + + assertThat(list.fastUnorderedRemove(10), is(10)); + + assertThat(list.size(), is(count - 1)); + assertThat(list.getInt(10), is(19)); + } + @Test public void shouldForEachOrderedInt() {