diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 022bb3fcae5..782791be0eb 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -195,7 +195,10 @@ The
- * This method buffers the input internally using - * {@code BufferedReader} if they are not already buffered. + * This method buffers the input internally using {@code BufferedReader} if they are not already buffered. *
* - * @param reader1 the first reader - * @param reader2 the second reader - * @return true if the content of the readers are equal or they both don't - * exist, false otherwise + * @param input1 the first reader + * @param input2 the second reader + * @return true if the content of the readers are equal or they both don't exist, false otherwise * @throws NullPointerException if either input is null - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs * @since 1.1 */ @SuppressWarnings("resource") - public static boolean contentEquals(final Reader reader1, final Reader reader2) - throws IOException { - if (reader1 == reader2) { + public static boolean contentEquals(final Reader input1, final Reader input2) throws IOException { + if (input1 == input2) { return true; } - if (reader1 == null ^ reader2 == null) { + if (input1 == null || input2 == null) { return false; } - final BufferedReader bufferedInput1 = toBufferedReader(reader1); - final BufferedReader bufferedInput2 = toBufferedReader(reader2); - int ch = bufferedInput1.read(); - while (EOF != ch) { - final int ch2 = bufferedInput2.read(); - if (ch != ch2) { - return false; + final char[] array1 = new char[DEFAULT_BUFFER_SIZE]; + final char[] array2 = new char[DEFAULT_BUFFER_SIZE]; + int pos1; + int pos2; + int count1; + int count2; + while (true) { + pos1 = 0; + pos2 = 0; + for (int index = 0; index < DEFAULT_BUFFER_SIZE; index++) { + if (pos1 == index) { + do { + count1 = input1.read(array1, pos1, DEFAULT_BUFFER_SIZE - pos1); + } while (count1 == 0); + if (count1 == EOF) { + return pos2 == index && input2.read() == EOF; + } + pos1 += count1; + } + if (pos2 == index) { + do { + count2 = input2.read(array2, pos2, DEFAULT_BUFFER_SIZE - pos2); + } while (count2 == 0); + if (count2 == EOF) { + return pos1 == index && input1.read() == EOF; + } + pos2 += count2; + } + if (array1[index] != array2[index]) { + return false; + } } - ch = bufferedInput1.read(); } - - return bufferedInput2.read() == EOF; } /** diff --git a/src/test/java/org/apache/commons/io/jmh/IOUtilsContentEqualsReadersBenchmark.java b/src/test/java/org/apache/commons/io/jmh/IOUtilsContentEqualsReadersBenchmark.java index 763eab78b11..1d365503370 100644 --- a/src/test/java/org/apache/commons/io/jmh/IOUtilsContentEqualsReadersBenchmark.java +++ b/src/test/java/org/apache/commons/io/jmh/IOUtilsContentEqualsReadersBenchmark.java @@ -45,12 +45,12 @@ * Test different implementations of {@link IOUtils#contentEquals(Reader, Reader)}. * *- * IOUtilsContentEqualsReadersBenchmark.testFileCurrent avgt 5 1984542.440 ▒ 741983.929 ns/op - * IOUtilsContentEqualsReadersBenchmark.testFilePr118 avgt 5 1903047.996 ▒ 1126067.279 ns/op - * IOUtilsContentEqualsReadersBenchmark.testFileRelease_2_8_0 avgt 5 2000614.270 ▒ 577200.820 ns/op - * IOUtilsContentEqualsReadersBenchmark.testStringCurrent avgt 5 4833065053.333 ▒ 313253734.966 ns/op - * IOUtilsContentEqualsReadersBenchmark.testStringPr118 avgt 5 1032292548.000 ▒ 32968762.278 ns/op - * IOUtilsContentEqualsReadersBenchmark.testStringRelease_2_8_0 avgt 5 4810962660.000 ▒ 221405909.807 ns/op + * IOUtilsContentEqualsReadersBenchmark.testFileCurrent avgt 5 1670968.050 ▒ 67526.308 ns/op + * IOUtilsContentEqualsReadersBenchmark.testFilePr118 avgt 5 1660143.543 ▒ 733178.893 ns/op + * IOUtilsContentEqualsReadersBenchmark.testFileRelease_2_8_0 avgt 5 1785283.975 ▒ 214177.764 ns/op + * IOUtilsContentEqualsReadersBenchmark.testStringCurrent avgt 5 1144495273.333 ▒ 50706166.907 ns/op + * IOUtilsContentEqualsReadersBenchmark.testStringPr118 avgt 5 1075059231.455 ▒ 275364676.487 ns/op + * IOUtilsContentEqualsReadersBenchmark.testStringRelease_2_8_0 avgt 5 4767157193.333 ▒ 139567775.251 ns/op **/ @BenchmarkMode(Mode.AverageTime) @@ -61,6 +61,7 @@ @Fork(value = 1, jvmArgs = {"-server"}) public class IOUtilsContentEqualsReadersBenchmark { + private static final int STRING_LEN = 1 << 24; private static final String TEST_PATH_A = "/org/apache/commons/io/testfileBOM.xml"; private static final String TEST_PATH_16K_A = "/org/apache/commons/io/abitmorethan16k.txt"; private static final String TEST_PATH_16K_A_COPY = "/org/apache/commons/io/abitmorethan16kcopy.txt"; @@ -69,15 +70,15 @@ public class IOUtilsContentEqualsReadersBenchmark { static String[] STRINGS = new String[5]; static { - STRINGS[0] = StringUtils.repeat("ab", 1 << 24); + STRINGS[0] = StringUtils.repeat("ab", STRING_LEN); STRINGS[1] = STRINGS[0] + 'c'; STRINGS[2] = STRINGS[0] + 'd'; - STRINGS[3] = StringUtils.repeat("ab\rab\n", 1 << 24); - STRINGS[4] = StringUtils.repeat("ab\r\nab\r", 1 << 24); + STRINGS[3] = StringUtils.repeat("ab\rab\n", STRING_LEN); + STRINGS[4] = StringUtils.repeat("ab\r\nab\r", STRING_LEN); } - static String SPECIAL_CASE_STRING_0 = StringUtils.repeat(StringUtils.repeat("ab", 1 << 24) + '\n', 2); - static String SPECIAL_CASE_STRING_1 = StringUtils.repeat(StringUtils.repeat("cd", 1 << 24) + '\n', 2); + static String SPECIAL_CASE_STRING_0 = StringUtils.repeat(StringUtils.repeat("ab", STRING_LEN) + '\n', 2); + static String SPECIAL_CASE_STRING_1 = StringUtils.repeat(StringUtils.repeat("cd", STRING_LEN) + '\n', 2); @SuppressWarnings("resource") public static boolean contentEquals_release_2_8_0(final Reader input1, final Reader input2) throws IOException {