From b0ca1fe04b0285bd31b7e399afe98a2eec37bd52 Mon Sep 17 00:00:00 2001 From: Alexey Pelykh Date: Thu, 17 Oct 2024 10:18:45 +0200 Subject: [PATCH] (feat) MemoizingSupplier.isMemoized --- .../com/google/common/base/SuppliersTest.java | 17 ++++---- .../src/com/google/common/base/Suppliers.java | 41 +++++++++++++++---- .../com/google/common/base/SuppliersTest.java | 17 ++++---- .../src/com/google/common/base/Suppliers.java | 41 +++++++++++++++---- 4 files changed, 86 insertions(+), 30 deletions(-) diff --git a/android/guava-tests/test/com/google/common/base/SuppliersTest.java b/android/guava-tests/test/com/google/common/base/SuppliersTest.java index 9a1150a0fc02..09c14edc85b8 100644 --- a/android/guava-tests/test/com/google/common/base/SuppliersTest.java +++ b/android/guava-tests/test/com/google/common/base/SuppliersTest.java @@ -80,15 +80,16 @@ static class SerializableThrowingSupplier extends ThrowingSupplier implements Se private static final long serialVersionUID = 0L; } - static void checkMemoize(CountingSupplier countingSupplier, Supplier memoizedSupplier) { + static void checkMemoize(CountingSupplier countingSupplier, + Suppliers.MemoizingSupplier memoizedSupplier) { // the underlying supplier hasn't executed yet assertEquals(0, countingSupplier.calls); - + assertFalse(memoizedSupplier.isMemoized()); assertEquals(10, (int) memoizedSupplier.get()); // now it has assertEquals(1, countingSupplier.calls); - + assertTrue(memoizedSupplier.isMemoized()); assertEquals(10, (int) memoizedSupplier.get()); // it still should only have executed once due to memoization @@ -101,7 +102,7 @@ public void testMemoize() { } private void memoizeTest(CountingSupplier countingSupplier) { - Supplier memoizedSupplier = Suppliers.memoize(countingSupplier); + Suppliers.MemoizingSupplier memoizedSupplier = Suppliers.memoize(countingSupplier); checkMemoize(countingSupplier, memoizedSupplier); } @@ -138,7 +139,7 @@ private void memoizeExceptionThrownTest(ThrowingSupplier throwingSupplier) { @GwtIncompatible // SerializableTester public void testMemoizeNonSerializable() throws Exception { CountingSupplier countingSupplier = new CountingSupplier(); - Supplier memoizedSupplier = Suppliers.memoize(countingSupplier); + Suppliers.MemoizingSupplier memoizedSupplier = Suppliers.memoize(countingSupplier); assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)"); checkMemoize(countingSupplier, memoizedSupplier); // Calls to the original memoized supplier shouldn't affect its copy. @@ -155,7 +156,7 @@ public void testMemoizeNonSerializable() throws Exception { @GwtIncompatible // SerializableTester public void testMemoizeSerializable() throws Exception { SerializableCountingSupplier countingSupplier = new SerializableCountingSupplier(); - Supplier memoizedSupplier = Suppliers.memoize(countingSupplier); + Suppliers.MemoizingSupplier memoizedSupplier = Suppliers.memoize(countingSupplier); assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)"); checkMemoize(countingSupplier, memoizedSupplier); // Calls to the original memoized supplier shouldn't affect its copy. @@ -163,11 +164,11 @@ public void testMemoizeSerializable() throws Exception { assertThat(memoizedSupplier.toString()) .isEqualTo("Suppliers.memoize()"); - Supplier copy = reserialize(memoizedSupplier); + Suppliers.MemoizingSupplier copy = reserialize(memoizedSupplier); Object unused2 = memoizedSupplier.get(); CountingSupplier countingCopy = - (CountingSupplier) ((Suppliers.MemoizingSupplier) copy).delegate; + (CountingSupplier) ((Suppliers.SerializableMemoizingSupplier) copy).delegate; checkMemoize(countingCopy, copy); } diff --git a/android/guava/src/com/google/common/base/Suppliers.java b/android/guava/src/com/google/common/base/Suppliers.java index 9476c21872fc..4c0428802955 100644 --- a/android/guava/src/com/google/common/base/Suppliers.java +++ b/android/guava/src/com/google/common/base/Suppliers.java @@ -110,18 +110,34 @@ public String toString() { *

If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is * returned directly. */ - public static Supplier memoize(Supplier delegate) { + public static MemoizingSupplier memoize(Supplier delegate) { if (delegate instanceof NonSerializableMemoizingSupplier - || delegate instanceof MemoizingSupplier) { - return delegate; + || delegate instanceof SerializableMemoizingSupplier) { + return (MemoizingSupplier) delegate; } return delegate instanceof Serializable - ? new MemoizingSupplier(delegate) + ? new SerializableMemoizingSupplier(delegate) : new NonSerializableMemoizingSupplier(delegate); } + /** + * A supplier that memoizes the result of the first call to {@link #get()} and returns the same + * result on subsequent calls to {@link #get()}. + * + * @author Alexey Pelykh + */ + @ElementTypesAreNonnullByDefault + public interface MemoizingSupplier extends Supplier { + /** + * Returns {@code true} if the supplier has been initialized, i.e. if the first call to + * {@link #get()} has been made or if the supplier has been explicitly initialized. + */ + boolean isMemoized(); + } + @VisibleForTesting - static class MemoizingSupplier implements Supplier, Serializable { + static class SerializableMemoizingSupplier + implements MemoizingSupplier, Serializable { private transient Object lock = new Object(); final Supplier delegate; @@ -130,7 +146,7 @@ static class MemoizingSupplier implements Supplier delegate) { + SerializableMemoizingSupplier(Supplier delegate) { this.delegate = checkNotNull(delegate); } @@ -154,6 +170,11 @@ public T get() { return uncheckedCastNullableTToT(value); } + @Override + public boolean isMemoized() { + return initialized; + } + @Override public String toString() { return "Suppliers.memoize(" @@ -172,7 +193,8 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE } @VisibleForTesting - static class NonSerializableMemoizingSupplier implements Supplier { + static class NonSerializableMemoizingSupplier + implements MemoizingSupplier { private final Object lock = new Object(); @SuppressWarnings("UnnecessaryLambda") // Must be a fixed singleton object @@ -208,6 +230,11 @@ public T get() { return uncheckedCastNullableTToT(value); } + @Override + public boolean isMemoized() { + return delegate == SUCCESSFULLY_COMPUTED; + } + @Override public String toString() { Supplier delegate = this.delegate; diff --git a/guava-tests/test/com/google/common/base/SuppliersTest.java b/guava-tests/test/com/google/common/base/SuppliersTest.java index 9a1150a0fc02..09c14edc85b8 100644 --- a/guava-tests/test/com/google/common/base/SuppliersTest.java +++ b/guava-tests/test/com/google/common/base/SuppliersTest.java @@ -80,15 +80,16 @@ static class SerializableThrowingSupplier extends ThrowingSupplier implements Se private static final long serialVersionUID = 0L; } - static void checkMemoize(CountingSupplier countingSupplier, Supplier memoizedSupplier) { + static void checkMemoize(CountingSupplier countingSupplier, + Suppliers.MemoizingSupplier memoizedSupplier) { // the underlying supplier hasn't executed yet assertEquals(0, countingSupplier.calls); - + assertFalse(memoizedSupplier.isMemoized()); assertEquals(10, (int) memoizedSupplier.get()); // now it has assertEquals(1, countingSupplier.calls); - + assertTrue(memoizedSupplier.isMemoized()); assertEquals(10, (int) memoizedSupplier.get()); // it still should only have executed once due to memoization @@ -101,7 +102,7 @@ public void testMemoize() { } private void memoizeTest(CountingSupplier countingSupplier) { - Supplier memoizedSupplier = Suppliers.memoize(countingSupplier); + Suppliers.MemoizingSupplier memoizedSupplier = Suppliers.memoize(countingSupplier); checkMemoize(countingSupplier, memoizedSupplier); } @@ -138,7 +139,7 @@ private void memoizeExceptionThrownTest(ThrowingSupplier throwingSupplier) { @GwtIncompatible // SerializableTester public void testMemoizeNonSerializable() throws Exception { CountingSupplier countingSupplier = new CountingSupplier(); - Supplier memoizedSupplier = Suppliers.memoize(countingSupplier); + Suppliers.MemoizingSupplier memoizedSupplier = Suppliers.memoize(countingSupplier); assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)"); checkMemoize(countingSupplier, memoizedSupplier); // Calls to the original memoized supplier shouldn't affect its copy. @@ -155,7 +156,7 @@ public void testMemoizeNonSerializable() throws Exception { @GwtIncompatible // SerializableTester public void testMemoizeSerializable() throws Exception { SerializableCountingSupplier countingSupplier = new SerializableCountingSupplier(); - Supplier memoizedSupplier = Suppliers.memoize(countingSupplier); + Suppliers.MemoizingSupplier memoizedSupplier = Suppliers.memoize(countingSupplier); assertThat(memoizedSupplier.toString()).isEqualTo("Suppliers.memoize(CountingSupplier)"); checkMemoize(countingSupplier, memoizedSupplier); // Calls to the original memoized supplier shouldn't affect its copy. @@ -163,11 +164,11 @@ public void testMemoizeSerializable() throws Exception { assertThat(memoizedSupplier.toString()) .isEqualTo("Suppliers.memoize()"); - Supplier copy = reserialize(memoizedSupplier); + Suppliers.MemoizingSupplier copy = reserialize(memoizedSupplier); Object unused2 = memoizedSupplier.get(); CountingSupplier countingCopy = - (CountingSupplier) ((Suppliers.MemoizingSupplier) copy).delegate; + (CountingSupplier) ((Suppliers.SerializableMemoizingSupplier) copy).delegate; checkMemoize(countingCopy, copy); } diff --git a/guava/src/com/google/common/base/Suppliers.java b/guava/src/com/google/common/base/Suppliers.java index 9476c21872fc..4c0428802955 100644 --- a/guava/src/com/google/common/base/Suppliers.java +++ b/guava/src/com/google/common/base/Suppliers.java @@ -110,18 +110,34 @@ public String toString() { *

If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is * returned directly. */ - public static Supplier memoize(Supplier delegate) { + public static MemoizingSupplier memoize(Supplier delegate) { if (delegate instanceof NonSerializableMemoizingSupplier - || delegate instanceof MemoizingSupplier) { - return delegate; + || delegate instanceof SerializableMemoizingSupplier) { + return (MemoizingSupplier) delegate; } return delegate instanceof Serializable - ? new MemoizingSupplier(delegate) + ? new SerializableMemoizingSupplier(delegate) : new NonSerializableMemoizingSupplier(delegate); } + /** + * A supplier that memoizes the result of the first call to {@link #get()} and returns the same + * result on subsequent calls to {@link #get()}. + * + * @author Alexey Pelykh + */ + @ElementTypesAreNonnullByDefault + public interface MemoizingSupplier extends Supplier { + /** + * Returns {@code true} if the supplier has been initialized, i.e. if the first call to + * {@link #get()} has been made or if the supplier has been explicitly initialized. + */ + boolean isMemoized(); + } + @VisibleForTesting - static class MemoizingSupplier implements Supplier, Serializable { + static class SerializableMemoizingSupplier + implements MemoizingSupplier, Serializable { private transient Object lock = new Object(); final Supplier delegate; @@ -130,7 +146,7 @@ static class MemoizingSupplier implements Supplier delegate) { + SerializableMemoizingSupplier(Supplier delegate) { this.delegate = checkNotNull(delegate); } @@ -154,6 +170,11 @@ public T get() { return uncheckedCastNullableTToT(value); } + @Override + public boolean isMemoized() { + return initialized; + } + @Override public String toString() { return "Suppliers.memoize(" @@ -172,7 +193,8 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE } @VisibleForTesting - static class NonSerializableMemoizingSupplier implements Supplier { + static class NonSerializableMemoizingSupplier + implements MemoizingSupplier { private final Object lock = new Object(); @SuppressWarnings("UnnecessaryLambda") // Must be a fixed singleton object @@ -208,6 +230,11 @@ public T get() { return uncheckedCastNullableTToT(value); } + @Override + public boolean isMemoized() { + return delegate == SUCCESSFULLY_COMPUTED; + } + @Override public String toString() { Supplier delegate = this.delegate;