Commit 99b3028b authored by Andrew Grieve's avatar Andrew Grieve Committed by Commit Bot

UnownedUserDataKey: Refactor lambda -> loops

Noticed this in binary size review as having a lot of nested classes.
Also removes most explicit null checks in favor of implicit ones.

Bug: None
Change-Id: I9777788512371b497c4236f16073a2b342e1acb5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419121Reviewed-by: default avatarTommy Nyquist <nyquist@chromium.org>
Commit-Queue: Andrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811247}
parent 06655eb1
...@@ -9,10 +9,11 @@ import androidx.annotation.Nullable; ...@@ -9,10 +9,11 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
/** /**
* UnownedUserDataKey is used in conjunction with a particular {@link UnownedUserData} as the key * UnownedUserDataKey is used in conjunction with a particular {@link UnownedUserData} as the key
...@@ -60,14 +61,6 @@ import java.util.concurrent.atomic.AtomicReference; ...@@ -60,14 +61,6 @@ import java.util.concurrent.atomic.AtomicReference;
* @see UnownedUserData for the marker interface used for this type of data. * @see UnownedUserData for the marker interface used for this type of data.
*/ */
public final class UnownedUserDataKey<T extends UnownedUserData> { public final class UnownedUserDataKey<T extends UnownedUserData> {
private interface Predicate<T> {
boolean test(T t);
}
private interface Action<T> {
void execute(T t, WeakReference<T> weakT);
}
@NonNull @NonNull
private final Class<T> mClazz; private final Class<T> mClazz;
private final Set<WeakReference<UnownedUserDataHost>> mHostAttachments = new HashSet<>(); private final Set<WeakReference<UnownedUserDataHost>> mHostAttachments = new HashSet<>();
...@@ -94,15 +87,14 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -94,15 +87,14 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
* @param object The object to attach. * @param object The object to attach.
*/ */
public final void attachToHost(@NonNull UnownedUserDataHost host, @NonNull T object) { public final void attachToHost(@NonNull UnownedUserDataHost host, @NonNull T object) {
checkNotNull(host); Objects.requireNonNull(object);
checkNotNull(object);
// Setting a new value might lead to detachment of previously attached data, including // Setting a new value might lead to detachment of previously attached data, including
// re-entry to this key, to happen before we update the {@link #mHostAttachments}. // re-entry to this key, to happen before we update the {@link #mHostAttachments}.
host.set(this, object); host.set(this, object);
AtomicReference<UnownedUserDataHost> retrievedHost = new AtomicReference<>(); if (!isAttachedToHost(host)) {
executeHostAction(host::equals, (attachedHost, unused) -> retrievedHost.set(attachedHost)); mHostAttachments.add(new WeakReference<>(host));
if (retrievedHost.get() == null) mHostAttachments.add(new WeakReference<>(host)); }
} }
/** /**
...@@ -116,12 +108,12 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -116,12 +108,12 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
*/ */
@Nullable @Nullable
public final T retrieveDataFromHost(@NonNull UnownedUserDataHost host) { public final T retrieveDataFromHost(@NonNull UnownedUserDataHost host) {
checkNotNull(host); for (UnownedUserDataHost attachedHost : getStrongRefs()) {
if (host.equals(attachedHost)) {
AtomicReference<T> retrievedValue = new AtomicReference<>(); return host.get(this);
executeHostAction( }
host::equals, (attachedHost, unused) -> retrievedValue.set(host.get(this))); }
return retrievedValue.get(); return null;
} }
/** /**
...@@ -131,11 +123,11 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -131,11 +123,11 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
* @param host The host to detach from. * @param host The host to detach from.
*/ */
public final void detachFromHost(@NonNull UnownedUserDataHost host) { public final void detachFromHost(@NonNull UnownedUserDataHost host) {
checkNotNull(host); for (UnownedUserDataHost attachedHost : getStrongRefs()) {
executeHostAction(host::equals, (attachedHost, weakAttachedHost) -> { if (host.equals(attachedHost)) {
attachedHost.remove(this); removeHostAttachment(attachedHost);
mHostAttachments.remove(weakAttachedHost); }
}); }
} }
/** /**
...@@ -143,13 +135,11 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -143,13 +135,11 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
* this key. It is OK to call this for already detached objects. * this key. It is OK to call this for already detached objects.
*/ */
public final void detachFromAllHosts(@NonNull T object) { public final void detachFromAllHosts(@NonNull T object) {
checkNotNull(object); for (UnownedUserDataHost attachedHost : getStrongRefs()) {
executeHostAction((attachedHost) if (object.equals(attachedHost.get(this))) {
-> object.equals(attachedHost.get(this)), removeHostAttachment(attachedHost);
(attachedHost, weakAttachedHost) -> { }
attachedHost.remove(this); }
mHostAttachments.remove(weakAttachedHost);
});
} }
/** /**
...@@ -159,7 +149,6 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -159,7 +149,6 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
* @return true if currently attached, false otherwise. * @return true if currently attached, false otherwise.
*/ */
public final boolean isAttachedToHost(@NonNull UnownedUserDataHost host) { public final boolean isAttachedToHost(@NonNull UnownedUserDataHost host) {
checkNotNull(host);
T t = retrieveDataFromHost(host); T t = retrieveDataFromHost(host);
return t != null; return t != null;
} }
...@@ -168,21 +157,35 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -168,21 +157,35 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
* @return Whether the {@link UnownedUserData} is currently attached to any hosts with this key. * @return Whether the {@link UnownedUserData} is currently attached to any hosts with this key.
*/ */
public final boolean isAttachedToAnyHost(@NonNull T object) { public final boolean isAttachedToAnyHost(@NonNull T object) {
checkNotNull(object);
return getHostAttachmentCount(object) > 0; return getHostAttachmentCount(object) > 0;
} }
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
/* package */ int getHostAttachmentCount(@NonNull T object) { /* package */ int getHostAttachmentCount(@NonNull T object) {
AtomicInteger count = new AtomicInteger(0); int ret = 0;
executeHostAction((attachedHost) for (UnownedUserDataHost attachedHost : getStrongRefs()) {
-> object.equals(attachedHost.get(this)), if (object.equals(attachedHost.get(this))) {
(attachedHost, unused) -> count.incrementAndGet()); ret++;
return count.get(); }
}
return ret;
} }
private void executeHostAction(@NonNull Predicate<UnownedUserDataHost> predicate, private void removeHostAttachment(UnownedUserDataHost host) {
@NonNull Action<UnownedUserDataHost> action) { host.remove(this);
for (WeakReference<UnownedUserDataHost> hostWeakReference : mHostAttachments) {
if (host.equals(hostWeakReference.get())) {
// Modifying mHostAttachments while iterating over it is okay here because we
// break out of the loop right away.
mHostAttachments.remove(hostWeakReference);
return;
}
}
}
// TODO(https://crbug.com/1131047): Make a //base helper for this.
private Collection<UnownedUserDataHost> getStrongRefs() {
ArrayList<UnownedUserDataHost> ret = new ArrayList<>();
Set<WeakReference<UnownedUserDataHost>> hosts = new HashSet<>(mHostAttachments); Set<WeakReference<UnownedUserDataHost>> hosts = new HashSet<>(mHostAttachments);
for (WeakReference<UnownedUserDataHost> hostWeakReference : hosts) { for (WeakReference<UnownedUserDataHost> hostWeakReference : hosts) {
UnownedUserDataHost hostStrongReference = hostWeakReference.get(); UnownedUserDataHost hostStrongReference = hostWeakReference.get();
...@@ -191,23 +194,11 @@ public final class UnownedUserDataKey<T extends UnownedUserData> { ...@@ -191,23 +194,11 @@ public final class UnownedUserDataKey<T extends UnownedUserData> {
continue; continue;
} }
if (hostStrongReference.isDestroyed()) { if (hostStrongReference.isDestroyed()) {
throw new IllegalStateException("Host should have been removed already."); assert false : "Host should have been removed already.";
throw new IllegalStateException();
} }
if (!predicate.test(hostStrongReference)) continue; ret.add(hostStrongReference);
action.execute(hostStrongReference, hostWeakReference);
}
}
private void checkNotNull(T unownedUserData) {
if (unownedUserData == null) {
throw new IllegalArgumentException("UnownedUserData can not be null.");
}
}
private static void checkNotNull(UnownedUserDataHost host) {
if (host == null) {
throw new IllegalArgumentException("UnownedUserDataHost can not be null.");
} }
return ret;
} }
} }
...@@ -843,14 +843,17 @@ public class UnownedUserDataKeyTest { ...@@ -843,14 +843,17 @@ public class UnownedUserDataKeyTest {
@Test @Test
public void testNullKeyOrDataShouldBeDisallowed() { public void testNullKeyOrDataShouldBeDisallowed() {
assertThrows(IllegalArgumentException.class, () -> Foo.KEY.attachToHost(null, null)); assertThrows(NullPointerException.class, () -> Foo.KEY.attachToHost(null, null));
assertThrows(IllegalArgumentException.class, () -> Foo.KEY.attachToHost(mHost1, null)); assertThrows(NullPointerException.class, () -> Foo.KEY.attachToHost(mHost1, null));
assertThrows(IllegalArgumentException.class, () -> Foo.KEY.attachToHost(null, mFoo)); assertThrows(NullPointerException.class, () -> Foo.KEY.attachToHost(null, mFoo));
assertThrows(IllegalArgumentException.class, () -> Foo.KEY.retrieveDataFromHost(null)); // Need a non-empty registry to avoid no-op.
Foo.KEY.attachToHost(mHost1, mFoo);
assertThrows(NullPointerException.class, () -> Foo.KEY.retrieveDataFromHost(null));
assertThrows(IllegalArgumentException.class, () -> Foo.KEY.detachFromHost(null)); assertThrows(NullPointerException.class, () -> Foo.KEY.detachFromHost(null));
assertThrows(IllegalArgumentException.class, () -> Foo.KEY.detachFromAllHosts(null)); assertThrows(NullPointerException.class, () -> Foo.KEY.detachFromAllHosts(null));
Foo.KEY.detachFromAllHosts(mFoo);
} }
@Test @Test
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment