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:19 UTC

[commons-lang] branch master updated (d416608 -> e0cfe47)

This is an automated email from the ASF dual-hosted git repository.

chtompki pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git.


    from d416608  Adding Javadocs for the Locks.Lock class. Improvements in the test suite.
     new 5673884  performance improve.
     new 3ef823e  performance improve.
     new 68cb8af  Revert "performance improve."
     new dee8f6f  implement lastIndexOf
     new 217da1e  implement lastIndexOf
     new 05724b2  reformat test
     new 73438e4  fix checkstyle
     new 00ecd33  fix checkstyle
     new bbc2e7e  refine tests
     new d02958c  refine tests
     new a9dea5e  refine tests
     new 249d9e4  refine tests
     new e04966a  refine tests
     new acaf458  LANG-1549: Thanks Jin
     new bf7aa89  Adding Javadocs for the Locks.Lock class. Improvements in the test suite.
     new e0cfe47  Merge branch 'master' of github.com:apache/commons-lang into LANG-1549

The 16 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 pom.xml                                            |  3 +
 src/changes/changes.xml                            |  1 +
 .../apache/commons/lang3/CharSequenceUtils.java    | 91 +++++++++++++++++---
 .../commons/lang3/CharSequenceUtilsTest.java       | 96 +++++++++++++++++++++-
 4 files changed, 179 insertions(+), 12 deletions(-)


[commons-lang] 15/16: Adding Javadocs for the Locks.Lock class. Improvements in the test suite.

Posted by ch...@apache.org.
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 bf7aa89ca45706ad1f40cacdf7448626529dd6b0
Author: Jochen Wiedmann <jo...@gmail.com>
AuthorDate: Fri Jun 26 11:51:06 2020 +0200

    Adding Javadocs for the Locks.Lock class. Improvements in the test suite.
---
 .../org/apache/commons/lang3/concurrent/Locks.java | 178 ++++++++++++++++++++-
 .../apache/commons/lang3/concurrent/LocksTest.java |  37 +++++
 2 files changed, 213 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/concurrent/Locks.java b/src/main/java/org/apache/commons/lang3/concurrent/Locks.java
index 28df9c0..48e16eb 100644
--- a/src/main/java/org/apache/commons/lang3/concurrent/Locks.java
+++ b/src/main/java/org/apache/commons/lang3/concurrent/Locks.java
@@ -70,31 +70,174 @@ import org.apache.commons.lang3.function.FailableFunction;
  */
 public class Locks {
 
+    /**
+     * This class implements a wrapper for a locked (hidden) object, and
+     * provides the means to access it. The basic idea, is that the user
+     * code forsakes all references to the locked object, using only the
+     * wrapper object, and the accessor methods
+     * {@link #acceptReadLocked(FailableConsumer)},
+     * {@link #acceptWriteLocked(FailableConsumer)},
+     * {@link #applyReadLocked(FailableFunction)}, and
+     * {@link #applyWriteLocked(FailableFunction)}. By doing so, the
+     * necessary protections are guaranteed.
+     * @param <O> The locked (hidden) objects type.
+     *
+     * @since 3.11
+     */
     public static class Lock<O extends Object> {
-
         private final StampedLock lock = new StampedLock();
         private final O lockedObject;
 
+        /**
+         * Creates a new instance with the given locked object. This
+         * constructor is supposed to be used for subclassing only.
+         * In general, it is suggested to use {@link Locks#lock(Object)}
+         * instead.
+         * @param lockedObject The locked (hidden) object. The caller is
+         * supposed to drop all references to the locked object.
+         */
         public Lock(final O lockedObject) {
             this.lockedObject = Objects.requireNonNull(lockedObject, "Locked Object");
         }
 
+        /**
+         * Provides read (shared, non-exclusive) access to the locked (hidden) object.
+         * More precisely, what the method will do (in the given order):
+         * <ol>
+         *   <li>Obtain a read (shared) lock on the locked (hidden) object.
+         *     The current thread may block, until such a lock is granted.
+         *   </li>
+         *   <li>Invokes the given {@link FailableConsumer consumer}, passing the
+         *   locked object as the parameter.</li>
+         *   <li>Release the lock, as soon as the consumers invocation is done.
+         *     If the invocation results in an error, the lock will be released
+         *     anyways.
+         *   </li>
+         * </ol>
+         * @param consumer The consumer, which is being invoked to use the
+         *   hidden object, which will be passed as the consumers parameter.
+         * @see #acceptWriteLocked(FailableConsumer)
+         * @see #applyReadLocked(FailableFunction)
+         */
         public void acceptReadLocked(final FailableConsumer<O, ?> consumer) {
             lockAcceptUnlock(() -> lock.readLock(), consumer);
         }
 
+        /**
+         * Provides write (exclusive) access to the locked (hidden) object.
+         * More precisely, what the method will do (in the given order):
+         * <ol>
+         *   <li>Obtain a write (shared) lock on the locked (hidden) object.
+         *     The current thread may block, until such a lock is granted.
+         *   </li>
+         *   <li>Invokes the given {@link FailableConsumer consumer}, passing the
+         *   locked object as the parameter.</li>
+         *   <li>Release the lock, as soon as the consumers invocation is done.
+         *     If the invocation results in an error, the lock will be released
+         *     anyways.
+         *   </li>
+         * </ol>
+         * @param consumer The consumer, which is being invoked to use the
+         *   hidden object, which will be passed as the consumers parameter.
+         * @see #acceptReadLocked(FailableConsumer)
+         * @see #applyWriteLocked(FailableFunction)
+         */
         public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) {
             lockAcceptUnlock(() -> lock.writeLock(), consumer);
         }
 
+        /**
+         * Provides read (shared, non-exclusive) access to the locked (hidden)
+         * object for the purpose of computing a result object.
+         * More precisely, what the method will do (in the given order):
+         * <ol>
+         *   <li>Obtain a read (shared) lock on the locked (hidden) object.
+         *     The current thread may block, until such a lock is granted.
+         *   </li>
+         *   <li>Invokes the given {@link FailableFunction function}, passing the
+         *   locked object as the parameter, receiving the functions result.</li>
+         *   <li>Release the lock, as soon as the consumers invocation is done.
+         *     If the invocation results in an error, the lock will be released
+         *     anyways.
+         *   </li>
+         *   <li>
+         *     Return the result object, that has been received from the
+         *     functions invocation.</li>
+         * </ol>
+         *
+         * <em>Example:</em> Suggest, that the hidden object is a list, and we
+         * wish to know the current size of the list. This might be achieved
+         * with the following:
+         *
+         * <pre>
+         *   private Lock&lt;List&lt;Object&gt;&gt; listLock;
+         *
+         *   public int getCurrentListSize() {
+         *       final Integer sizeInteger
+         *           = listLock.applyReadLocked((list) -&gt; Integer.valueOf(list.size));
+         *       return sizeInteger.intValue();
+         *   }
+         * </pre>
+         * @param <T> The result type (both the functions, and this method's.)
+         * @param function The function, which is being invoked to compute the
+         *   result. The function will receive the hidden object.
+         * @return The result object, which has been returned by the
+         *   functions invocation.
+         * @throws IllegalStateException The result object would be, in fact,
+         *   the hidden object. This would extend access to the hidden object
+         *   beyond this methods lifetime and will therefore be prevented.
+         * @see #acceptReadLocked(FailableConsumer)
+         * @see #applyWriteLocked(FailableFunction)
+         */
         public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) {
             return lockApplyUnlock(() -> lock.readLock(), function);
         }
 
+        /**
+         * Provides write (exclusive) access to the locked (hidden)
+         * object for the purpose of computing a result object.
+         * More precisely, what the method will do (in the given order):
+         * <ol>
+         *   <li>Obtain a read (shared) lock on the locked (hidden) object.
+         *     The current thread may block, until such a lock is granted.
+         *   </li>
+         *   <li>Invokes the given {@link FailableFunction function}, passing the
+         *   locked object as the parameter, receiving the functions result.</li>
+         *   <li>Release the lock, as soon as the consumers invocation is done.
+         *     If the invocation results in an error, the lock will be released
+         *     anyways.
+         *   </li>
+         *   <li>
+         *     Return the result object, that has been received from the
+         *     functions invocation.</li>
+         * </ol>
+         * @param <T> The result type (both the functions, and this method's.)
+         * @param function The function, which is being invoked to compute the
+         *   result. The function will receive the hidden object.
+         * @return The result object, which has been returned by the
+         *   functions invocation.
+         * @throws IllegalStateException The result object would be, in fact,
+         *   the hidden object. This would extend access to the hidden object
+         *   beyond this methods lifetime and will therefore be prevented.
+         * @see #acceptReadLocked(FailableConsumer)
+         * @see #applyWriteLocked(FailableFunction)
+         */
         public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) {
             return lockApplyUnlock(() -> lock.writeLock(), function);
         }
 
+        /**
+         * This method provides the actual implementation for
+         * {@link #acceptReadLocked(FailableConsumer)}, and
+         * {@link #acceptWriteLocked(FailableConsumer)}.
+         * @param stampSupplier A supplier for the lock. (This provides, in
+         *   fact, a long, because a {@link StampedLock} is used internally.)
+         * @param consumer The consumer, which is to be given access to the
+         *   locked (hidden) object, which will be passed as a parameter.
+         * @see #acceptReadLocked(FailableConsumer)
+         * @see #acceptWriteLocked(FailableConsumer)
+         * @see #lockApplyUnlock(LongSupplier, FailableFunction)
+         */
         protected void lockAcceptUnlock(final LongSupplier stampSupplier, final FailableConsumer<O, ?> consumer) {
             final long stamp = stampSupplier.getAsLong();
             try {
@@ -106,10 +249,33 @@ public class Locks {
             }
         }
 
+        /**
+         * This method provides the actual implementation for
+         * {@link #applyReadLocked(FailableFunction)}, and
+         * {@link #applyWriteLocked(FailableFunction)}.
+         * @param <T> The result type (both the functions, and this method's.)
+         * @param stampSupplier A supplier for the lock. (This provides, in
+         *   fact, a long, because a {@link StampedLock} is used internally.)
+         * @param function The function, which is being invoked to compute
+         *   the result object. This function will receive the locked (hidden)
+         *   object as a parameter.
+         * @return The result object, which has been returned by the
+         *   functions invocation.
+         * @throws IllegalStateException The result object would be, in fact,
+         *   the hidden object. This would extend access to the hidden object
+         *   beyond this methods lifetime and will therefore be prevented.
+         * @see #applyReadLocked(FailableFunction)
+         * @see #applyWriteLocked(FailableFunction)
+         * @see #lockAcceptUnlock(LongSupplier, FailableConsumer)
+         */
         protected <T> T lockApplyUnlock(final LongSupplier stampSupplier, final FailableFunction<O, T, ?> function) {
             final long stamp = stampSupplier.getAsLong();
             try {
-                return function.apply(lockedObject);
+                final T t = function.apply(lockedObject);
+                if (t == lockedObject) {
+                    throw new IllegalStateException("The returned object is, in fact, the hidden object.");
+                }
+                return t;
             } catch (final Throwable t) {
                 throw Failable.rethrow(t);
             } finally {
@@ -118,6 +284,14 @@ public class Locks {
         }
     }
 
+    /**
+     * Creates a new instance of {@link Lock} with the given locked
+     * (hidden) object.
+     * @param <O> The locked objects type.
+     * @param object The locked (hidden) object.
+     * @return The created instance, a {@link Lock lock} for the
+     * given object.
+     */
     public static <O extends Object> Locks.Lock<O> lock(final O object) {
         return new Locks.Lock<>(object);
     }
diff --git a/src/test/java/org/apache/commons/lang3/concurrent/LocksTest.java b/src/test/java/org/apache/commons/lang3/concurrent/LocksTest.java
index 2d577ec..706281e 100644
--- a/src/test/java/org/apache/commons/lang3/concurrent/LocksTest.java
+++ b/src/test/java/org/apache/commons/lang3/concurrent/LocksTest.java
@@ -16,7 +16,11 @@
  */
 package org.apache.commons.lang3.concurrent;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.util.function.LongConsumer;
 
@@ -36,6 +40,7 @@ public class LocksTest {
         runTest(DELAY, false, l -> assertTrue(l < NUMBER_OF_THREADS*DELAY));
     }
 
+    @Test
     public void testWriteLock() throws Exception {
         final long DELAY = 100;
         /** If our threads are running concurrently, then we expect to be no faster
@@ -44,6 +49,38 @@ public class LocksTest {
         runTest(DELAY, true, l -> assertTrue(l >= NUMBER_OF_THREADS*DELAY));
     }
 
+    @Test
+    public void testResultValidation() {
+        final Object hidden = new Object();
+        final Lock<Object> lock = Locks.lock(hidden);
+        final Object o1 = lock.applyReadLocked((h) -> {
+            return new Object();
+        });
+        assertNotNull(o1);
+        assertNotSame(hidden, o1);
+        final Object o2 = lock.applyWriteLocked((h) -> {
+            return new Object();
+        });
+        assertNotNull(o2);
+        assertNotSame(hidden, o2);
+        try {
+            lock.applyReadLocked((h) -> {
+                return hidden;
+            });
+            fail("Expected Exception");
+        } catch (IllegalStateException e) {
+            assertEquals("The returned object is, in fact, the hidden object.", e.getMessage());
+        }
+        try {
+            lock.applyReadLocked((h) -> {
+                return hidden;
+            });
+            fail("Expected Exception");
+        } catch (IllegalStateException e) {
+            assertEquals("The returned object is, in fact, the hidden object.", e.getMessage());
+        }
+    }
+
     private void runTest(final long delay, final boolean exclusiveLock, final LongConsumer runTimeCheck) throws InterruptedException {
         final boolean[] booleanValues = new boolean[10];
         final Lock<boolean[]> lock = Locks.lock(booleanValues);


[commons-lang] 06/16: reformat test

Posted by ch...@apache.org.
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 05724b2baa1d160f08132ff2038586e389048680
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 02:30:19 2020 +0800

    reformat test
---
 .../java/org/apache/commons/lang3/CharSequenceUtilsTest.java   | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index 796e8f2..5eb1c79 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -16,14 +16,20 @@
  */
 package org.apache.commons.lang3;
 
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.Random;
 import java.util.stream.IntStream;
 
-import static org.junit.jupiter.api.Assertions.*;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests CharSequenceUtils


[commons-lang] 08/16: fix checkstyle

Posted by ch...@apache.org.
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 00ecd339bdd8c977822d78c881667df3c211d146
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 05:59:32 2020 +0800

    fix checkstyle
---
 src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index 147a8e5..82f5751 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -191,7 +191,7 @@ public class CharSequenceUtilsTest {
     static class WrapperString implements CharSequence {
         private CharSequence inner;
 
-        public WrapperString(CharSequence inner) {
+        WrapperString(CharSequence inner) {
             this.inner = inner;
         }
 


[commons-lang] 02/16: performance improve.

Posted by ch...@apache.org.
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 3ef823e8e1ff4f12636fc78ab84de6042f6efd9f
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 00:48:14 2020 +0800

    performance improve.
---
 src/main/java/org/apache/commons/lang3/CharSequenceUtils.java | 10 +---------
 1 file changed, 1 insertion(+), 9 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..012a16d 100644
--- a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
@@ -251,15 +251,7 @@ public class CharSequenceUtils {
      * @return the resulting char array
      */
     static char[] toCharArray(final CharSequence cs) {
-        if (cs instanceof String) {
-            return ((String) cs).toCharArray();
-        }
-        final int sz = cs.length();
-        final char[] array = new char[cs.length()];
-        for (int i = 0; i < sz; i++) {
-            array[i] = cs.charAt(i);
-        }
-        return array;
+        return cs.toString().toCharArray();
     }
 
     /**


[commons-lang] 07/16: fix checkstyle

Posted by ch...@apache.org.
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 73438e431e9b4bd752ce901770499577d8f828f8
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 05:53:04 2020 +0800

    fix checkstyle
---
 src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index 5eb1c79..147a8e5 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -189,7 +189,7 @@ public class CharSequenceUtilsTest {
     }
 
     static class WrapperString implements CharSequence {
-        CharSequence inner;
+        private CharSequence inner;
 
         public WrapperString(CharSequence inner) {
             this.inner = inner;


[commons-lang] 01/16: performance improve.

Posted by ch...@apache.org.
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 567388428cab9b2aec090f4c1641a69feb6f5a5d
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 00:46:58 2020 +0800

    performance improve.
---
 .../java/org/apache/commons/lang3/CharSequenceUtils.java   | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
index c6af33a..0d9db8e 100644
--- a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
@@ -134,6 +134,13 @@ public class CharSequenceUtils {
      * @return the index where the search sequence was found
      */
     static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) {
+        if (cs instanceof String) {
+            return ((String) cs).indexOf(searchChar.toString(), start);
+        } else if (cs instanceof StringBuilder) {
+            return ((StringBuilder) cs).indexOf(searchChar.toString(), start);
+        } else if (cs instanceof StringBuffer) {
+            return ((StringBuffer) cs).indexOf(searchChar.toString(), start);
+        }
         return cs.toString().indexOf(searchChar.toString(), start);
 //        if (cs instanceof String && searchChar instanceof String) {
 //            // TODO: Do we assume searchChar is usually relatively small;
@@ -218,6 +225,13 @@ public class CharSequenceUtils {
      * @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);
+        }
         return cs.toString().lastIndexOf(searchChar.toString(), start);
 //        if (cs instanceof String && searchChar instanceof String) {
 //            // TODO: Do we assume searchChar is usually relatively small;


[commons-lang] 04/16: implement lastIndexOf

Posted by ch...@apache.org.
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
+        );
+    }
 }


[commons-lang] 12/16: refine tests

Posted by ch...@apache.org.
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 249d9e474459ab060fe6b702d32dc5e2873c8ed5
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 18:08:49 2020 +0800

    refine tests
---
 src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index e92fdda..fd0c875 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -31,8 +31,6 @@ import java.lang.reflect.Modifier;
 import java.util.Random;
 import java.util.stream.IntStream;
 
-import static org.junit.jupiter.api.Assertions.*;
-
 /**
  * Tests CharSequenceUtils
  */


[commons-lang] 11/16: refine tests

Posted by ch...@apache.org.
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 a9dea5e5c4484c28ee68c002fede54a6c9fcf1bb
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 18:03:12 2020 +0800

    refine tests
---
 src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index 32db044..e92fdda 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -16,6 +16,14 @@
  */
 package org.apache.commons.lang3;
 
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import org.junit.jupiter.api.Test;
 
 import java.lang.reflect.Constructor;


[commons-lang] 05/16: implement lastIndexOf

Posted by ch...@apache.org.
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 217da1e6aa2b2c9f626ed2efa42e3e3996175571
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 02:26:14 2020 +0800

    implement lastIndexOf
---
 .../apache/commons/lang3/CharSequenceUtils.java    | 31 +++++++++++++++-------
 .../commons/lang3/CharSequenceUtilsTest.java       | 23 +++-------------
 2 files changed, 25 insertions(+), 29 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
index 4dab063..01de17c 100644
--- a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
@@ -266,22 +266,33 @@ public class CharSequenceUtils {
             start = len1 - len2;
         }
 
-        if (check(cs, searchChar, len2, start)) {
-            return start;
-        }
+        char char0 = searchChar.charAt(0);
 
-        for (int i = start - 1; i >= 0; i--) {
-            if (check(cs, searchChar, len2, i)) {
+        int i = start;
+        while (true) {
+            while (cs.charAt(i) != char0) {
+                i--;
+                if (i < 0) {
+                    return -1;
+                }
+            }
+            if (checkLaterThan1(cs, searchChar, len2, i)) {
                 return i;
+            } else {
+                i--;
+                if (i < 0) {
+                    return -1;
+                }
             }
         }
-
-        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)) {
+    private static boolean checkLaterThan1(final CharSequence cs, final CharSequence searchChar, int len2, int start1) {
+        for (int i = 1, j = len2 - 1; i <= j; i++, j--) {
+            if (cs.charAt(start1 + i) != searchChar.charAt(i)
+                    ||
+                    cs.charAt(start1 + j) != searchChar.charAt(j)
+            ) {
                 return false;
             }
         }
diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index c230c45..796e8f2 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -16,23 +16,14 @@
  */
 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;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.Test;
 
 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;
+import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * Tests CharSequenceUtils
@@ -258,7 +249,7 @@ public class CharSequenceUtilsTest {
 
     private void testNewLastIndexOfSingle(CharSequence a, CharSequence b) {
         int maxa = Math.max(a.length(), b.length());
-        for (int i = -maxa-10; i <= maxa+10; i++) {
+        for (int i = -maxa - 10; i <= maxa + 10; i++) {
             testNewLastIndexOfSingle(a, b, i);
         }
     }
@@ -269,14 +260,8 @@ public class CharSequenceUtilsTest {
     }
 
     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,
+                a.toString().lastIndexOf(b.toString(), start),
                 CharSequenceUtils.lastIndexOf(new WrapperString(a.toString()), b.toString(), start),
                 "testNewLastIndexOf fails! original : " + a + " seg : " + b + " start : " + start
         );


[commons-lang] 09/16: refine tests

Posted by ch...@apache.org.
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 bbc2e7ee859287f84055b7637d92363cece9442c
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 17:17:52 2020 +0800

    refine tests
---
 .../apache/commons/lang3/CharSequenceUtilsTest.java   | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index 82f5751..b927808 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -16,20 +16,14 @@
  */
 package org.apache.commons.lang3;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import org.junit.jupiter.api.Test;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.Random;
 import java.util.stream.IntStream;
 
-import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
 
 /**
  * Tests CharSequenceUtils
@@ -236,6 +230,13 @@ public class CharSequenceUtilsTest {
         testNewLastIndexOfSingle("11", "1");
         testNewLastIndexOfSingle("1", "11");
 
+        testNewLastIndexOfSingle("apache", "a");
+        testNewLastIndexOfSingle("apache", "p");
+        testNewLastIndexOfSingle("apache", "e");
+        testNewLastIndexOfSingle("apache", "x");
+        testNewLastIndexOfSingle("oraoraoraora", "r");
+        testNewLastIndexOfSingle("mudamudamudamuda", "d");
+
         Random random = new Random();
         StringBuilder seg = new StringBuilder();
         while (seg.length() <= CharSequenceUtils.TO_STRING_LIMIT) {
@@ -258,6 +259,8 @@ public class CharSequenceUtilsTest {
         for (int i = -maxa - 10; i <= maxa + 10; i++) {
             testNewLastIndexOfSingle(a, b, i);
         }
+        testNewLastIndexOfSingle(a, b, Integer.MIN_VALUE);
+        testNewLastIndexOfSingle(a, b, Integer.MAX_VALUE);
     }
 
     private void testNewLastIndexOfSingle(CharSequence a, CharSequence b, int start) {


[commons-lang] 13/16: refine tests

Posted by ch...@apache.org.
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 e04966a6122ef94d295a070bf96774629e9f05a4
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 20:10:07 2020 +0800

    refine tests
---
 src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index fd0c875..fb9d568 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -24,12 +24,11 @@ import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import org.junit.jupiter.api.Test;
-
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.Random;
 import java.util.stream.IntStream;
+import org.junit.jupiter.api.Test;
 
 /**
  * Tests CharSequenceUtils


[commons-lang] 10/16: refine tests

Posted by ch...@apache.org.
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 d02958ca097c65f73bd51adbe246ff4d3ec07ca0
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 17:35:50 2020 +0800

    refine tests
---
 src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
index b927808..32db044 100644
--- a/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharSequenceUtilsTest.java
@@ -271,7 +271,7 @@ public class CharSequenceUtilsTest {
     private void testNewLastIndexOfSingleSingle(CharSequence a, CharSequence b, int start) {
         assertEquals(
                 a.toString().lastIndexOf(b.toString(), start),
-                CharSequenceUtils.lastIndexOf(new WrapperString(a.toString()), b.toString(), start),
+                CharSequenceUtils.lastIndexOf(new WrapperString(a.toString()), new WrapperString(b.toString()), start),
                 "testNewLastIndexOf fails! original : " + a + " seg : " + b + " start : " + start
         );
     }


[commons-lang] 16/16: Merge branch 'master' of github.com:apache/commons-lang into LANG-1549

Posted by ch...@apache.org.
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 e0cfe47b77d9a36c6b579b9b3fa3eb95c5c3c265
Merge: bf7aa89 d416608
Author: Rob Tompkins <ch...@apache.org>
AuthorDate: Fri Jun 26 05:54:12 2020 -0400

    Merge branch 'master' of github.com:apache/commons-lang into LANG-1549



[commons-lang] 03/16: Revert "performance improve."

Posted by ch...@apache.org.
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 68cb8af7e402041e33e931f33bc60a32d7b9ce95
Author: XenoAmess <xe...@gmail.com>
AuthorDate: Mon Jun 1 01:16:19 2020 +0800

    Revert "performance improve."
    
    This reverts commit 3b05b95a
---
 src/main/java/org/apache/commons/lang3/CharSequenceUtils.java | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
index 012a16d..0d9db8e 100644
--- a/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharSequenceUtils.java
@@ -251,7 +251,15 @@ public class CharSequenceUtils {
      * @return the resulting char array
      */
     static char[] toCharArray(final CharSequence cs) {
-        return cs.toString().toCharArray();
+        if (cs instanceof String) {
+            return ((String) cs).toCharArray();
+        }
+        final int sz = cs.length();
+        final char[] array = new char[cs.length()];
+        for (int i = 0; i < sz; i++) {
+            array[i] = cs.charAt(i);
+        }
+        return array;
     }
 
     /**


[commons-lang] 14/16: LANG-1549: Thanks Jin

Posted by ch...@apache.org.
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 acaf4582781c17952b25fe86abafcefa0489c2a6
Author: Rob Tompkins <ch...@apache.org>
AuthorDate: Fri Jun 26 05:49:12 2020 -0400

    LANG-1549: Thanks Jin
---
 pom.xml                 | 3 +++
 src/changes/changes.xml | 1 +
 2 files changed, 4 insertions(+)

diff --git a/pom.xml b/pom.xml
index c05b502..ca9d7f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -508,6 +508,9 @@
     <contributor>
       <name>Peter Verhas</name>
     </contributor>
+    <contributor>
+      <name>Jin Xu</name>
+    </contributor>
   </contributors>
 
   <!-- Lang should depend on very little -->
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 9c8259b..429f608 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -46,6 +46,7 @@ The <action> type attribute can be add,update,fix,remove.
   <body>
 
   <release version="3.11" date="2020-MM-DD" description="New features and bug fixes..">
+    <action issue="LANG-1549" type="update" dev="chtompki" due-to="Jin Xu">CharSequenceUtils.lastIndexOf : remake it</action>
     <action                   type="update" dev="kinow" due-to="XenoAmess">remove encoding and docEncoding and use inherited values from commons-parent</action>
     <action                   type="fix"    dev="kinow" due-to="contextshuffling">Fix Javadoc for StringUtils.appendIfMissingIgnoreCase() #507.</action>
     <action                   type="update" dev="ggregory" due-to="Isira Seneviratne, Bruno P. Kinoshita">Simplify null checks in Pair.hashCode() using Objects.hashCode(). #517.</action>