Skip to content

Commit

Permalink
(feat) MemoizingSupplier.isInitialized
Browse files Browse the repository at this point in the history
  • Loading branch information
alexey-pelykh committed Oct 17, 2024
1 parent 0e2fa3e commit f830a5e
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ static class SerializableThrowingSupplier extends ThrowingSupplier implements Se
static void checkMemoize(CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) {
// the underlying supplier hasn't executed yet
assertEquals(0, countingSupplier.calls);

assertFalse(memoizedSupplier.isInitialized());
assertEquals(10, (int) memoizedSupplier.get());

// now it has
assertEquals(1, countingSupplier.calls);

assertTrue(memoizedSupplier.isInitialized());
assertEquals(10, (int) memoizedSupplier.get());

// it still should only have executed once due to memoization
Expand Down Expand Up @@ -165,7 +165,7 @@ public void testMemoizeSerializable() throws Exception {
Object unused2 = memoizedSupplier.get();

CountingSupplier countingCopy =
(CountingSupplier) ((Suppliers.MemoizingSupplier<Integer>) copy).delegate;
(CountingSupplier) ((Suppliers.SerializableMemoizingSupplier<Integer>) copy).delegate;
checkMemoize(countingCopy, copy);
}

Expand Down
41 changes: 34 additions & 7 deletions android/guava/src/com/google/common/base/Suppliers.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,34 @@ public String toString() {
* <p>If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is
* returned directly.
*/
public static <T extends @Nullable Object> Supplier<T> memoize(Supplier<T> delegate) {
public static <T extends @Nullable Object> MemoizingSupplier<T> memoize(Supplier<T> delegate) {
if (delegate instanceof NonSerializableMemoizingSupplier
|| delegate instanceof MemoizingSupplier) {
return delegate;
|| delegate instanceof SerializableMemoizingSupplier) {
return (MemoizingSupplier<T>) delegate;
}
return delegate instanceof Serializable
? new MemoizingSupplier<T>(delegate)
? new SerializableMemoizingSupplier<T>(delegate)
: new NonSerializableMemoizingSupplier<T>(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<T extends @Nullable Object> extends Supplier<T> {
/**
* 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 isInitialized();
}

@VisibleForTesting
static class MemoizingSupplier<T extends @Nullable Object> implements Supplier<T>, Serializable {
static class SerializableMemoizingSupplier<T extends @Nullable Object>
implements MemoizingSupplier<T>, Serializable {
private transient Object lock = new Object();

final Supplier<T> delegate;
Expand All @@ -130,7 +146,7 @@ static class MemoizingSupplier<T extends @Nullable Object> implements Supplier<T
// on volatile read of "initialized".
@CheckForNull transient T value;

MemoizingSupplier(Supplier<T> delegate) {
SerializableMemoizingSupplier(Supplier<T> delegate) {
this.delegate = checkNotNull(delegate);
}

Expand All @@ -154,6 +170,11 @@ public T get() {
return uncheckedCastNullableTToT(value);
}

@Override
public boolean isInitialized() {
return initialized;
}

@Override
public String toString() {
return "Suppliers.memoize("
Expand All @@ -172,7 +193,8 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
}

@VisibleForTesting
static class NonSerializableMemoizingSupplier<T extends @Nullable Object> implements Supplier<T> {
static class NonSerializableMemoizingSupplier<T extends @Nullable Object>
implements MemoizingSupplier<T> {
private final Object lock = new Object();

@SuppressWarnings("UnnecessaryLambda") // Must be a fixed singleton object
Expand Down Expand Up @@ -208,6 +230,11 @@ public T get() {
return uncheckedCastNullableTToT(value);
}

@Override
public boolean isInitialized() {
return delegate == SUCCESSFULLY_COMPUTED;
}

@Override
public String toString() {
Supplier<T> delegate = this.delegate;
Expand Down
6 changes: 3 additions & 3 deletions guava-tests/test/com/google/common/base/SuppliersTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@ static class SerializableThrowingSupplier extends ThrowingSupplier implements Se
static void checkMemoize(CountingSupplier countingSupplier, Supplier<Integer> memoizedSupplier) {
// the underlying supplier hasn't executed yet
assertEquals(0, countingSupplier.calls);

assertFalse(memoizedSupplier.isInitialized());
assertEquals(10, (int) memoizedSupplier.get());

// now it has
assertEquals(1, countingSupplier.calls);

assertTrue(memoizedSupplier.isInitialized());
assertEquals(10, (int) memoizedSupplier.get());

// it still should only have executed once due to memoization
Expand Down Expand Up @@ -165,7 +165,7 @@ public void testMemoizeSerializable() throws Exception {
Object unused2 = memoizedSupplier.get();

CountingSupplier countingCopy =
(CountingSupplier) ((Suppliers.MemoizingSupplier<Integer>) copy).delegate;
(CountingSupplier) ((Suppliers.SerializableMemoizingSupplier<Integer>) copy).delegate;
checkMemoize(countingCopy, copy);
}

Expand Down
41 changes: 34 additions & 7 deletions guava/src/com/google/common/base/Suppliers.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,34 @@ public String toString() {
* <p>If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is
* returned directly.
*/
public static <T extends @Nullable Object> Supplier<T> memoize(Supplier<T> delegate) {
public static <T extends @Nullable Object> MemoizingSupplier<T> memoize(Supplier<T> delegate) {
if (delegate instanceof NonSerializableMemoizingSupplier
|| delegate instanceof MemoizingSupplier) {
return delegate;
|| delegate instanceof SerializableMemoizingSupplier) {
return (MemoizingSupplier<T>) delegate;
}
return delegate instanceof Serializable
? new MemoizingSupplier<T>(delegate)
? new SerializableMemoizingSupplier<T>(delegate)
: new NonSerializableMemoizingSupplier<T>(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<T extends @Nullable Object> extends Supplier<T> {
/**
* 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 isInitialized();
}

@VisibleForTesting
static class MemoizingSupplier<T extends @Nullable Object> implements Supplier<T>, Serializable {
static class SerializableMemoizingSupplier<T extends @Nullable Object>
implements MemoizingSupplier<T>, Serializable {
private transient Object lock = new Object();

final Supplier<T> delegate;
Expand All @@ -130,7 +146,7 @@ static class MemoizingSupplier<T extends @Nullable Object> implements Supplier<T
// on volatile read of "initialized".
@CheckForNull transient T value;

MemoizingSupplier(Supplier<T> delegate) {
SerializableMemoizingSupplier(Supplier<T> delegate) {
this.delegate = checkNotNull(delegate);
}

Expand All @@ -154,6 +170,11 @@ public T get() {
return uncheckedCastNullableTToT(value);
}

@Override
public boolean isInitialized() {
return initialized;
}

@Override
public String toString() {
return "Suppliers.memoize("
Expand All @@ -172,7 +193,8 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
}

@VisibleForTesting
static class NonSerializableMemoizingSupplier<T extends @Nullable Object> implements Supplier<T> {
static class NonSerializableMemoizingSupplier<T extends @Nullable Object>
implements MemoizingSupplier<T> {
private final Object lock = new Object();

@SuppressWarnings("UnnecessaryLambda") // Must be a fixed singleton object
Expand Down Expand Up @@ -208,6 +230,11 @@ public T get() {
return uncheckedCastNullableTToT(value);
}

@Override
public boolean isInitialized() {
return delegate == SUCCESSFULLY_COMPUTED;
}

@Override
public String toString() {
Supplier<T> delegate = this.delegate;
Expand Down

0 comments on commit f830a5e

Please sign in to comment.