Skip to content

Commit

Permalink
Adds rotate() for arrays of ints.
Browse files Browse the repository at this point in the history
RELNOTES=Adds rotate() for arrays of ints.
PiperOrigin-RevId: 443706002
  • Loading branch information
java-team-github-bot authored and Google Java Core Libraries committed Apr 22, 2022
1 parent ac878a5 commit cd338fa
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,103 @@ public void testReverseIndexed() {
testReverse(new int[] {-1, 1, -2, 2}, 1, 3, new int[] {-1, -2, 1, 2});
}

private static void testRotate(int[] input, int distance, int[] expectedOutput) {
input = Arrays.copyOf(input, input.length);
Ints.rotate(input, distance);
assertThat(input).isEqualTo(expectedOutput);
}

private static void testRotate(
int[] input, int distance, int fromIndex, int toIndex, int[] expectedOutput) {
input = Arrays.copyOf(input, input.length);
Ints.rotate(input, distance, fromIndex, toIndex);
assertThat(input).isEqualTo(expectedOutput);
}

public void testRotate() {
testRotate(new int[] {}, -1, new int[] {});
testRotate(new int[] {}, 0, new int[] {});
testRotate(new int[] {}, 1, new int[] {});

testRotate(new int[] {1}, -2, new int[] {1});
testRotate(new int[] {1}, -1, new int[] {1});
testRotate(new int[] {1}, 0, new int[] {1});
testRotate(new int[] {1}, 1, new int[] {1});
testRotate(new int[] {1}, 2, new int[] {1});

testRotate(new int[] {1, 2}, -3, new int[] {2, 1});
testRotate(new int[] {1, 2}, -1, new int[] {2, 1});
testRotate(new int[] {1, 2}, -2, new int[] {1, 2});
testRotate(new int[] {1, 2}, 0, new int[] {1, 2});
testRotate(new int[] {1, 2}, 1, new int[] {2, 1});
testRotate(new int[] {1, 2}, 2, new int[] {1, 2});
testRotate(new int[] {1, 2}, 3, new int[] {2, 1});

testRotate(new int[] {1, 2, 3}, -5, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, -4, new int[] {2, 3, 1});
testRotate(new int[] {1, 2, 3}, -3, new int[] {1, 2, 3});
testRotate(new int[] {1, 2, 3}, -2, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, -1, new int[] {2, 3, 1});
testRotate(new int[] {1, 2, 3}, 0, new int[] {1, 2, 3});
testRotate(new int[] {1, 2, 3}, 1, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, 2, new int[] {2, 3, 1});
testRotate(new int[] {1, 2, 3}, 3, new int[] {1, 2, 3});
testRotate(new int[] {1, 2, 3}, 4, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, 5, new int[] {2, 3, 1});

testRotate(new int[] {1, 2, 3, 4}, -9, new int[] {2, 3, 4, 1});
testRotate(new int[] {1, 2, 3, 4}, -5, new int[] {2, 3, 4, 1});
testRotate(new int[] {1, 2, 3, 4}, -1, new int[] {2, 3, 4, 1});
testRotate(new int[] {1, 2, 3, 4}, 0, new int[] {1, 2, 3, 4});
testRotate(new int[] {1, 2, 3, 4}, 1, new int[] {4, 1, 2, 3});
testRotate(new int[] {1, 2, 3, 4}, 5, new int[] {4, 1, 2, 3});
testRotate(new int[] {1, 2, 3, 4}, 9, new int[] {4, 1, 2, 3});

testRotate(new int[] {1, 2, 3, 4, 5}, -6, new int[] {2, 3, 4, 5, 1});
testRotate(new int[] {1, 2, 3, 4, 5}, -4, new int[] {5, 1, 2, 3, 4});
testRotate(new int[] {1, 2, 3, 4, 5}, -3, new int[] {4, 5, 1, 2, 3});
testRotate(new int[] {1, 2, 3, 4, 5}, -1, new int[] {2, 3, 4, 5, 1});
testRotate(new int[] {1, 2, 3, 4, 5}, 0, new int[] {1, 2, 3, 4, 5});
testRotate(new int[] {1, 2, 3, 4, 5}, 1, new int[] {5, 1, 2, 3, 4});
testRotate(new int[] {1, 2, 3, 4, 5}, 3, new int[] {3, 4, 5, 1, 2});
testRotate(new int[] {1, 2, 3, 4, 5}, 4, new int[] {2, 3, 4, 5, 1});
testRotate(new int[] {1, 2, 3, 4, 5}, 6, new int[] {5, 1, 2, 3, 4});
}

public void testRotateIndexed() {
testRotate(new int[] {}, 0, 0, 0, new int[] {});

testRotate(new int[] {1}, 0, 0, 1, new int[] {1});
testRotate(new int[] {1}, 1, 0, 1, new int[] {1});
testRotate(new int[] {1}, 1, 1, 1, new int[] {1});

// Rotate the central 5 elements, leaving the ends as-is
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -6, 1, 6, new int[] {0, 2, 3, 4, 5, 1, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -1, 1, 6, new int[] {0, 2, 3, 4, 5, 1, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 0, 1, 6, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 5, 1, 6, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 14, 1, 6, new int[] {0, 2, 3, 4, 5, 1, 6});

// Rotate the first three elements
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -2, 0, 3, new int[] {2, 0, 1, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -1, 0, 3, new int[] {1, 2, 0, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 0, 0, 3, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 1, 0, 3, new int[] {2, 0, 1, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 2, 0, 3, new int[] {1, 2, 0, 3, 4, 5, 6});

// Rotate the last four elements
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -6, 3, 7, new int[] {0, 1, 2, 5, 6, 3, 4});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -5, 3, 7, new int[] {0, 1, 2, 4, 5, 6, 3});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -4, 3, 7, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -3, 3, 7, new int[] {0, 1, 2, 6, 3, 4, 5});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -2, 3, 7, new int[] {0, 1, 2, 5, 6, 3, 4});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -1, 3, 7, new int[] {0, 1, 2, 4, 5, 6, 3});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 0, 3, 7, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 1, 3, 7, new int[] {0, 1, 2, 6, 3, 4, 5});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 2, 3, 7, new int[] {0, 1, 2, 5, 6, 3, 4});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 3, 3, 7, new int[] {0, 1, 2, 4, 5, 6, 3});
}

public void testSortDescending() {
testSortDescending(new int[] {}, new int[] {});
testSortDescending(new int[] {1}, new int[] {1});
Expand Down
46 changes: 46 additions & 0 deletions android/guava/src/com/google/common/primitives/Ints.java
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,52 @@ public static void reverse(int[] array, int fromIndex, int toIndex) {
}
}

/**
* Performs a right rotation of {@code array} of "distance" places, so that the first element is
* moved to index "distance", and the element at index {@code i} ends up at index {@code (distance
* + i) mod array.length}. This is equivalent to {@code Collections.rotate(Ints.asList(array),
* distance)}, but is considerably faster and avoids allocation and garbage collection.
*
* <p>The provided "distance" may be negative, which will rotate left.
*/
public static void rotate(int[] array, int distance) {
rotate(array, distance, 0, array.length);
}

/**
* Performs a right rotation of {@code array} between {@code fromIndex} inclusive and {@code
* toIndex} exclusive. This is equivalent to {@code
* Collections.rotate(Ints.asList(array).subList(fromIndex, toIndex), distance)}, but is
* considerably faster and avoids allocations and garbage collection.
*
* <p>The provided "distance" may be negative, which will rotate left.
*
* @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
* {@code toIndex > fromIndex}
*/
public static void rotate(int[] array, int distance, int fromIndex, int toIndex) {
checkNotNull(array);
checkPositionIndexes(fromIndex, toIndex, array.length);
if (array.length <= 1) {
return;
}

int length = toIndex - fromIndex;
// Obtain m = (-distance mod length), a non-negative value less than "length". This is how many
// places left to rotate.
int m = -distance % length;
m = (m < 0) ? m + length : m;
// The current index of what will become the first element of the rotated section.
int newFirstIndex = m + fromIndex;
if (newFirstIndex == fromIndex) {
return;
}

reverse(array, fromIndex, newFirstIndex);
reverse(array, newFirstIndex, toIndex);
reverse(array, fromIndex, toIndex);
}

/**
* Returns an array containing each value of {@code collection}, converted to a {@code int} value
* in the manner of {@link Number#intValue}.
Expand Down
97 changes: 97 additions & 0 deletions guava-tests/test/com/google/common/primitives/IntsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,103 @@ public void testReverseIndexed() {
testReverse(new int[] {-1, 1, -2, 2}, 1, 3, new int[] {-1, -2, 1, 2});
}

private static void testRotate(int[] input, int distance, int[] expectedOutput) {
input = Arrays.copyOf(input, input.length);
Ints.rotate(input, distance);
assertThat(input).isEqualTo(expectedOutput);
}

private static void testRotate(
int[] input, int distance, int fromIndex, int toIndex, int[] expectedOutput) {
input = Arrays.copyOf(input, input.length);
Ints.rotate(input, distance, fromIndex, toIndex);
assertThat(input).isEqualTo(expectedOutput);
}

public void testRotate() {
testRotate(new int[] {}, -1, new int[] {});
testRotate(new int[] {}, 0, new int[] {});
testRotate(new int[] {}, 1, new int[] {});

testRotate(new int[] {1}, -2, new int[] {1});
testRotate(new int[] {1}, -1, new int[] {1});
testRotate(new int[] {1}, 0, new int[] {1});
testRotate(new int[] {1}, 1, new int[] {1});
testRotate(new int[] {1}, 2, new int[] {1});

testRotate(new int[] {1, 2}, -3, new int[] {2, 1});
testRotate(new int[] {1, 2}, -1, new int[] {2, 1});
testRotate(new int[] {1, 2}, -2, new int[] {1, 2});
testRotate(new int[] {1, 2}, 0, new int[] {1, 2});
testRotate(new int[] {1, 2}, 1, new int[] {2, 1});
testRotate(new int[] {1, 2}, 2, new int[] {1, 2});
testRotate(new int[] {1, 2}, 3, new int[] {2, 1});

testRotate(new int[] {1, 2, 3}, -5, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, -4, new int[] {2, 3, 1});
testRotate(new int[] {1, 2, 3}, -3, new int[] {1, 2, 3});
testRotate(new int[] {1, 2, 3}, -2, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, -1, new int[] {2, 3, 1});
testRotate(new int[] {1, 2, 3}, 0, new int[] {1, 2, 3});
testRotate(new int[] {1, 2, 3}, 1, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, 2, new int[] {2, 3, 1});
testRotate(new int[] {1, 2, 3}, 3, new int[] {1, 2, 3});
testRotate(new int[] {1, 2, 3}, 4, new int[] {3, 1, 2});
testRotate(new int[] {1, 2, 3}, 5, new int[] {2, 3, 1});

testRotate(new int[] {1, 2, 3, 4}, -9, new int[] {2, 3, 4, 1});
testRotate(new int[] {1, 2, 3, 4}, -5, new int[] {2, 3, 4, 1});
testRotate(new int[] {1, 2, 3, 4}, -1, new int[] {2, 3, 4, 1});
testRotate(new int[] {1, 2, 3, 4}, 0, new int[] {1, 2, 3, 4});
testRotate(new int[] {1, 2, 3, 4}, 1, new int[] {4, 1, 2, 3});
testRotate(new int[] {1, 2, 3, 4}, 5, new int[] {4, 1, 2, 3});
testRotate(new int[] {1, 2, 3, 4}, 9, new int[] {4, 1, 2, 3});

testRotate(new int[] {1, 2, 3, 4, 5}, -6, new int[] {2, 3, 4, 5, 1});
testRotate(new int[] {1, 2, 3, 4, 5}, -4, new int[] {5, 1, 2, 3, 4});
testRotate(new int[] {1, 2, 3, 4, 5}, -3, new int[] {4, 5, 1, 2, 3});
testRotate(new int[] {1, 2, 3, 4, 5}, -1, new int[] {2, 3, 4, 5, 1});
testRotate(new int[] {1, 2, 3, 4, 5}, 0, new int[] {1, 2, 3, 4, 5});
testRotate(new int[] {1, 2, 3, 4, 5}, 1, new int[] {5, 1, 2, 3, 4});
testRotate(new int[] {1, 2, 3, 4, 5}, 3, new int[] {3, 4, 5, 1, 2});
testRotate(new int[] {1, 2, 3, 4, 5}, 4, new int[] {2, 3, 4, 5, 1});
testRotate(new int[] {1, 2, 3, 4, 5}, 6, new int[] {5, 1, 2, 3, 4});
}

public void testRotateIndexed() {
testRotate(new int[] {}, 0, 0, 0, new int[] {});

testRotate(new int[] {1}, 0, 0, 1, new int[] {1});
testRotate(new int[] {1}, 1, 0, 1, new int[] {1});
testRotate(new int[] {1}, 1, 1, 1, new int[] {1});

// Rotate the central 5 elements, leaving the ends as-is
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -6, 1, 6, new int[] {0, 2, 3, 4, 5, 1, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -1, 1, 6, new int[] {0, 2, 3, 4, 5, 1, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 0, 1, 6, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 5, 1, 6, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 14, 1, 6, new int[] {0, 2, 3, 4, 5, 1, 6});

// Rotate the first three elements
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -2, 0, 3, new int[] {2, 0, 1, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -1, 0, 3, new int[] {1, 2, 0, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 0, 0, 3, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 1, 0, 3, new int[] {2, 0, 1, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 2, 0, 3, new int[] {1, 2, 0, 3, 4, 5, 6});

// Rotate the last four elements
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -6, 3, 7, new int[] {0, 1, 2, 5, 6, 3, 4});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -5, 3, 7, new int[] {0, 1, 2, 4, 5, 6, 3});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -4, 3, 7, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -3, 3, 7, new int[] {0, 1, 2, 6, 3, 4, 5});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -2, 3, 7, new int[] {0, 1, 2, 5, 6, 3, 4});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, -1, 3, 7, new int[] {0, 1, 2, 4, 5, 6, 3});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 0, 3, 7, new int[] {0, 1, 2, 3, 4, 5, 6});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 1, 3, 7, new int[] {0, 1, 2, 6, 3, 4, 5});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 2, 3, 7, new int[] {0, 1, 2, 5, 6, 3, 4});
testRotate(new int[] {0, 1, 2, 3, 4, 5, 6}, 3, 3, 7, new int[] {0, 1, 2, 4, 5, 6, 3});
}

public void testSortDescending() {
testSortDescending(new int[] {}, new int[] {});
testSortDescending(new int[] {1}, new int[] {1});
Expand Down
46 changes: 46 additions & 0 deletions guava/src/com/google/common/primitives/Ints.java
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,52 @@ public static void reverse(int[] array, int fromIndex, int toIndex) {
}
}

/**
* Performs a right rotation of {@code array} of "distance" places, so that the first element is
* moved to index "distance", and the element at index {@code i} ends up at index {@code (distance
* + i) mod array.length}. This is equivalent to {@code Collections.rotate(Ints.asList(array),
* distance)}, but is considerably faster and avoids allocation and garbage collection.
*
* <p>The provided "distance" may be negative, which will rotate left.
*/
public static void rotate(int[] array, int distance) {
rotate(array, distance, 0, array.length);
}

/**
* Performs a right rotation of {@code array} between {@code fromIndex} inclusive and {@code
* toIndex} exclusive. This is equivalent to {@code
* Collections.rotate(Ints.asList(array).subList(fromIndex, toIndex), distance)}, but is
* considerably faster and avoids allocations and garbage collection.
*
* <p>The provided "distance" may be negative, which will rotate left.
*
* @throws IndexOutOfBoundsException if {@code fromIndex < 0}, {@code toIndex > array.length}, or
* {@code toIndex > fromIndex}
*/
public static void rotate(int[] array, int distance, int fromIndex, int toIndex) {
checkNotNull(array);
checkPositionIndexes(fromIndex, toIndex, array.length);
if (array.length <= 1) {
return;
}

int length = toIndex - fromIndex;
// Obtain m = (-distance mod length), a non-negative value less than "length". This is how many
// places left to rotate.
int m = -distance % length;
m = (m < 0) ? m + length : m;
// The current index of what will become the first element of the rotated section.
int newFirstIndex = m + fromIndex;
if (newFirstIndex == fromIndex) {
return;
}

reverse(array, fromIndex, newFirstIndex);
reverse(array, newFirstIndex, toIndex);
reverse(array, fromIndex, toIndex);
}

/**
* Returns an array containing each value of {@code collection}, converted to a {@code int} value
* in the manner of {@link Number#intValue}.
Expand Down

0 comments on commit cd338fa

Please sign in to comment.