You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ch...@apache.org on 2020/06/26 09:55:23 UTC
[commons-lang] 04/16: implement lastIndexOf
This is an automated email from the ASF dual-hosted git repository.
chtompki pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
commit dee8f6fb849fd3b7d928f13e273f8160f0a45f5b
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 01:51:43 2020 +0800
implement lastIndexOf
---
.../apache/commons/lang3/CharSequenceUtils.java | 78 ++++++++++++++----
.../commons/lang3/CharSequenceUtilsTest.java | 95 ++++++++++++++++++++++
2 files changed, 156 insertions(+), 17 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
index 0d9db8e..4dab063 100644
--- a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
@@ -216,6 +216,8 @@ public class CharSequenceUtils {
return NOT_FOUND;
}
+ static final int TO_STRING_LIMIT = 16;
+
/**
* Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf
*
@@ -224,24 +226,66 @@ public class CharSequenceUtils {
* @param start the start index
* @return the index where the search sequence was found
*/
- static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
- if (cs instanceof String) {
- return ((String) cs).lastIndexOf((String) searchChar, start);
- } else if (cs instanceof StringBuilder) {
- return ((StringBuilder) cs).lastIndexOf((String) searchChar, start);
- } else if (cs instanceof StringBuffer) {
- return ((StringBuffer) cs).lastIndexOf((String) searchChar, start);
+ static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, int start) {
+ if (searchChar instanceof String) {
+ if (cs instanceof String) {
+ return ((String) cs).lastIndexOf((String) searchChar, start);
+ } else if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).lastIndexOf((String) searchChar, start);
+ } else if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).lastIndexOf((String) searchChar, start);
+ }
}
- return cs.toString().lastIndexOf(searchChar.toString(), start);
-// if (cs instanceof String && searchChar instanceof String) {
-// // TODO: Do we assume searchChar is usually relatively small;
-// // If so then calling toString() on it is better than reverting to
-// // the green implementation in the else block
-// return ((String) cs).lastIndexOf((String) searchChar, start);
-// } else {
-// // TODO: Implement rather than convert to String
-// return cs.toString().lastIndexOf(searchChar.toString(), start);
-// }
+
+ int len1 = cs.length();
+ int len2 = searchChar.length();
+
+ if (start > len1) {
+ start = len1;
+ }
+
+ if (start < 0 || len2 < 0 || len2 > len1) {
+ return -1;
+ }
+
+ if (len2 == 0) {
+ return start;
+ }
+
+ if (len2 <= TO_STRING_LIMIT) {
+ if (cs instanceof String) {
+ return ((String) cs).lastIndexOf(searchChar.toString(), start);
+ } else if (cs instanceof StringBuilder) {
+ return ((StringBuilder) cs).lastIndexOf(searchChar.toString(), start);
+ } else if (cs instanceof StringBuffer) {
+ return ((StringBuffer) cs).lastIndexOf(searchChar.toString(), start);
+ }
+ }
+
+ if (start + len2 > len1) {
+ start = len1 - len2;
+ }
+
+ if (check(cs, searchChar, len2, start)) {
+ return start;
+ }
+
+ for (int i = start - 1; i >= 0; i--) {
+ if (check(cs, searchChar, len2, i)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ private static boolean check(final CharSequence cs, final CharSequence searchChar, int len2, int start1) {
+ for (int i = 0; i < len2; i++) {
+ if (cs.charAt(start1 + i) != searchChar.charAt(i)) {
+ return false;
+ }
+ }
+ return true;
}
/**
diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index e7dd3b4..c230c45 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -16,6 +16,7 @@
*/
package org.apache.commons.lang3;
+import static java.nio.CharBuffer.wrap;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -26,7 +27,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
+import java.nio.CharBuffer;
+import java.util.Random;
+import java.util.stream.IntStream;
+import org.apache.commons.lang3.text.StrBuilder;
import org.junit.jupiter.api.Test;
/**
@@ -186,4 +191,94 @@ public class CharSequenceUtilsTest {
assertArrayEquals(expected, CharSequenceUtils.toCharArray(builder.toString()));
}
+ static class WrapperString implements CharSequence {
+ CharSequence inner;
+
+ public WrapperString(CharSequence inner) {
+ this.inner = inner;
+ }
+
+ @Override
+ public int length() {
+ return inner.length();
+ }
+
+ @Override
+ public char charAt(int index) {
+ return inner.charAt(index);
+ }
+
+ @Override
+ public CharSequence subSequence(int start, int end) {
+ return inner.subSequence(start, end);
+ }
+
+ @Override
+ public String toString() {
+ return inner.toString();
+ }
+
+ @Override
+ public IntStream chars() {
+ return inner.chars();
+ }
+
+ @Override
+ public IntStream codePoints() {
+ return inner.codePoints();
+ }
+ }
+
+ @Test
+ public void testNewLastIndexOf() {
+ testNewLastIndexOfSingle("808087847-1321060740-635567660180086727-925755305", "-1321060740-635567660", 21);
+ testNewLastIndexOfSingle("", "");
+ testNewLastIndexOfSingle("1", "");
+ testNewLastIndexOfSingle("", "1");
+ testNewLastIndexOfSingle("1", "1");
+ testNewLastIndexOfSingle("11", "1");
+ testNewLastIndexOfSingle("1", "11");
+
+ Random random = new Random();
+ StringBuilder seg = new StringBuilder();
+ while (seg.length() <= CharSequenceUtils.TO_STRING_LIMIT) {
+ seg.append(random.nextInt());
+ }
+ StringBuilder original = new StringBuilder(seg);
+ testNewLastIndexOfSingle(original, seg);
+ for (int i = 0; i < 100; i++) {
+ if (random.nextDouble() < 0.5) {
+ original.append(random.nextInt() % 10);
+ } else {
+ original = new StringBuilder().append(String.valueOf(random.nextInt() % 100)).append(original);
+ }
+ testNewLastIndexOfSingle(original, seg);
+ }
+ }
+
+ private void testNewLastIndexOfSingle(CharSequence a, CharSequence b) {
+ int maxa = Math.max(a.length(), b.length());
+ for (int i = -maxa-10; i <= maxa+10; i++) {
+ testNewLastIndexOfSingle(a, b, i);
+ }
+ }
+
+ private void testNewLastIndexOfSingle(CharSequence a, CharSequence b, int start) {
+ testNewLastIndexOfSingleSingle(a, b, start);
+ testNewLastIndexOfSingleSingle(b, a, start);
+ }
+
+ private void testNewLastIndexOfSingleSingle(CharSequence a, CharSequence b, int start) {
+ int expected = a.toString().lastIndexOf(b.toString(), start);
+// assertEquals(
+// expected,
+// lastIndexOf(new WrapperString(a), b, start),
+// "testNewLastIndexOf fails! original : " + a + " seg : " + b + " start : " + start
+// );
+ assertEquals(
+ expected,
+ CharSequenceUtils.lastIndexOf(new WrapperString(a.toString()), b.toString(), start),
+ "testNewLastIndexOf fails! original : " + a + " seg : " + b + " start : " + start
+ );
+ }
}