Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce reference support submodule #140

Merged
merged 2 commits into from
Mar 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<module>io</module>
<module>net</module>
<module>os</module>
<module>ref</module>
<module>version</module>
<module>vertx-context</module>
</modules>
Expand Down
49 changes: 49 additions & 0 deletions ref/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.smallrye.common</groupId>
<artifactId>smallrye-common-parent</artifactId>
<version>1.10.1-SNAPSHOT</version>
</parent>

<artifactId>smallrye-common-ref</artifactId>

<name>SmallRye Common: References</name>

<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>smallrye-common-constraint</artifactId>
</dependency>
</dependencies>

<profiles>
<profile>
<id>coverage</id>
<properties>
<argLine>@{jacocoArgLine}</argLine>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
37 changes: 37 additions & 0 deletions ref/src/main/java/io/smallrye/common/ref/CleanerReference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.smallrye.common.ref;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
* A special version of {@link PhantomReference} that is strongly retained until it is reaped by the collection thread.
*/
public class CleanerReference<T, A> extends PhantomReference<T, A> {
private static final Set<CleanerReference<?, ?>> set = Collections
.newSetFromMap(new ConcurrentHashMap<CleanerReference<?, ?>, Boolean>());

/**
* Construct a new instance with a reaper.
*
* @param referent the referent
* @param attachment the attachment
* @param reaper the reaper to use
*/
public CleanerReference(final T referent, final A attachment, final Reaper<T, A> reaper) {
super(referent, attachment, reaper);
set.add(this);
}

void clean() {
set.remove(this);
}

public final int hashCode() {
return super.hashCode();
}

public final boolean equals(final Object obj) {
return super.equals(obj);
}
}
59 changes: 59 additions & 0 deletions ref/src/main/java/io/smallrye/common/ref/PhantomReference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.smallrye.common.ref;

import java.lang.ref.ReferenceQueue;

/**
* A reapable phantom reference with an attachment. If a {@link Reaper} is given, then it will be used to asynchronously
* clean up the referent.
*
* @param <T> the reference value type
* @param <A> the attachment type
*
* @see java.lang.ref.PhantomReference
*/
public class PhantomReference<T, A> extends java.lang.ref.PhantomReference<T> implements Reference<T, A>, Reapable<T, A> {
private final A attachment;
private final Reaper<T, A> reaper;

/**
* Construct a new instance with an explicit reference queue.
*
* @param referent the referent
* @param attachment the attachment
* @param q the reference queue to use
*/
public PhantomReference(final T referent, final A attachment, final ReferenceQueue<? super T> q) {
super(referent, q);
this.attachment = attachment;
reaper = null;
}

/**
* Construct a new instance with a reaper.
*
* @param referent the referent
* @param attachment the attachment
* @param reaper the reaper to use
*/
public PhantomReference(final T referent, final A attachment, final Reaper<T, A> reaper) {
super(referent, References.ReaperThread.REAPER_QUEUE);
this.reaper = reaper;
this.attachment = attachment;
}

public A getAttachment() {
return attachment;
}

public Type getType() {
return Type.PHANTOM;
}

public Reaper<T, A> getReaper() {
return reaper;
}

public String toString() {
return "phantom reference";
}
}
17 changes: 17 additions & 0 deletions ref/src/main/java/io/smallrye/common/ref/Reapable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.smallrye.common.ref;

/**
* A reference which is reapable (can be automatically collected).
*
* @param <T> the reference type
* @param <A> the reference attachment type
*/
interface Reapable<T, A> {

/**
* Get the associated reaper.
*
* @return the reaper
*/
Reaper<T, A> getReaper();
}
17 changes: 17 additions & 0 deletions ref/src/main/java/io/smallrye/common/ref/Reaper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.smallrye.common.ref;

/**
* A cleaner for a dead object.
*
* @param <T> the reference type
* @param <A> the reference attachment type
*/
public interface Reaper<T, A> {

/**
* Perform the cleanup action for a reference.
*
* @param reference the reference
*/
void reap(Reference<T, A> reference);
}
135 changes: 135 additions & 0 deletions ref/src/main/java/io/smallrye/common/ref/Reference.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package io.smallrye.common.ref;

import java.util.EnumSet;

/**
* An enhanced reference type with a type-safe attachment.
*
* @param <T> the reference value type
* @param <A> the attachment type
*
* @see java.lang.ref.Reference
*/
public interface Reference<T, A> {

/**
* Get the value, or {@code null} if the reference has been cleared.
*
* @return the value
*/
T get();

/**
* Get the attachment, if any.
*
* @return the attachment
*/
A getAttachment();

/**
* Clear the reference.
*/
void clear();

/**
* Get the type of the reference.
*
* @return the type
*/
Type getType();

/**
* A reference type.
*
* @apiviz.exclude
*/
enum Type {

/**
* A strong reference.
*/
STRONG,
/**
* A weak reference.
*/
WEAK,
/**
* A phantom reference.
*/
PHANTOM,
/**
* A soft reference.
*/
SOFT,
/**
* A {@code null} reference.
*/
NULL,
;

private static final int fullSize = values().length;

/**
* Determine whether the given set is fully populated (or "full"), meaning it contains all possible values.
*
* @param set the set
*
* @return {@code true} if the set is full, {@code false} otherwise
*/
public static boolean isFull(final EnumSet<Type> set) {
return set != null && set.size() == fullSize;
}

/**
* Determine whether this instance is equal to one of the given instances.
*
* @param v1 the first instance
*
* @return {@code true} if one of the instances matches this one, {@code false} otherwise
*/
public boolean in(final Type v1) {
return this == v1;
}

/**
* Determine whether this instance is equal to one of the given instances.
*
* @param v1 the first instance
* @param v2 the second instance
*
* @return {@code true} if one of the instances matches this one, {@code false} otherwise
*/
public boolean in(final Type v1, final Type v2) {
return this == v1 || this == v2;
}

/**
* Determine whether this instance is equal to one of the given instances.
*
* @param v1 the first instance
* @param v2 the second instance
* @param v3 the third instance
*
* @return {@code true} if one of the instances matches this one, {@code false} otherwise
*/
public boolean in(final Type v1, final Type v2, final Type v3) {
return this == v1 || this == v2 || this == v3;
}

/**
* Determine whether this instance is equal to one of the given instances.
*
* @param values the possible values
*
* @return {@code true} if one of the instances matches this one, {@code false} otherwise
*/
public boolean in(final Type... values) {
if (values != null)
for (Type value : values) {
if (this == value)
return true;
}
return false;
}
}
}
Loading