Skip to content

Commit 4e7dca9

Browse files
committed
Some javadoc
1 parent 05de6e9 commit 4e7dca9

21 files changed

+634
-75
lines changed

hypo-types/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ val typesExport = project(":types-export")
3535
tasks.test {
3636
dependsOn(typesExport.tasks.named("buildTypesExport"))
3737

38-
// systemProperty("hypo.interning.disabled", "true")
3938
val zipFile = typesExport.layout.buildDirectory.file("types-export/types-export.zip").get().asFile.absolutePath
4039
systemProperty("hypo.types.zip", zipFile)
4140
}

hypo-types/src/main/java/dev/denwav/hypo/types/HypoTypesUtil.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
import org.jetbrains.annotations.NotNull;
2323
import org.jetbrains.annotations.Nullable;
2424

25+
/**
26+
* General utility class used by {@code hypo-types}.
27+
*/
2528
public final class HypoTypesUtil {
2629

2730
private HypoTypesUtil() {}

hypo-types/src/main/java/dev/denwav/hypo/types/Intern.java

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@
2828
import org.jetbrains.annotations.NotNull;
2929
import org.jetbrains.annotations.Nullable;
3030

31+
/**
32+
* Interning base class which enables types classes to be interned, that is to say, prevent multiple copies of equal
33+
* values to exist on the heap. This is useful for two primary reasons: first, all type classes are pure data classes,
34+
* their identity is meaningless. Second, and more importantly, when analyzing large jar files with many classes many of
35+
* the same type descriptors will be encountered over and over again, and it would be an inefficient use of memory to
36+
* store separate copies for each type when they are identical. Common examples include core Java types just as
37+
* {@code Ljava/lang/Object;} and {@code Ljava/lang/String;}, but this also applies to extremely common method
38+
* descriptors and signatures, such as {@code ()V}, etc.
39+
*
40+
* <p>This is thread-safe, and utilizes a concurrent hashmap to enable lock-less handling of value instances.
41+
*
42+
* <p>The internal state of the internment can be checked via two static helper methods on this class,
43+
* {@link #tryFind(Class, String)} and {@link #internmentSize(Class)}.
44+
*
45+
* @param <T> The type of {@code this}. Any other type will result in a {@link ClassCastException} at runtime.
46+
*/
3147
public abstract class Intern<T extends Intern<T>> implements TypeRepresentable {
3248

3349
private static final IdentityHashMap<ConcurrentHashMap<String, WeakReference<?>>, AtomicLong> interns = new IdentityHashMap<>();
@@ -45,7 +61,6 @@ public abstract class Intern<T extends Intern<T>> implements TypeRepresentable {
4561
final var map = entry.getKey();
4662
final AtomicLong lastSize = entry.getValue();
4763
if (Math.abs(map.mappingCount() - lastSize.get()) < 10_000) {
48-
System.out.println("SKIPPED");
4964
continue;
5065
}
5166
map.values().removeIf(r -> r.get() == null);
@@ -82,6 +97,21 @@ protected ConcurrentHashMap<String, WeakReference<?>> computeValue(final @NotNul
8297

8398
private static final boolean interningDisabled = Boolean.getBoolean("hypo.interning.disabled");
8499

100+
/**
101+
* Return a class which is guaranteed to have the same value as {@code this}, but may be a different instance. An
102+
* interned value satisfies the following rule:
103+
* <ul>
104+
* <li>{@code obj.intern().equals(obj)}</li>
105+
* <li>{@code obj.equals(obj.intern())}</li>
106+
* </ul>
107+
*
108+
* If two objects exist, {@code o1} and {@code o2}, where {@code o1.equals(o2)}, then the following will also be true:
109+
* <ul>
110+
* <li>{@code o1.intern() == o2.intern()}</li>
111+
* </ul>
112+
*
113+
* @return Return the interned version of this object.
114+
*/
85115
public final T intern() {
86116
if (interningDisabled) {
87117
return HypoTypesUtil.cast(this);
@@ -97,15 +127,31 @@ public final T intern() {
97127
return res;
98128
}
99129

130+
// Edge case, handle scenarios where the reference returned from `map` was garbage collected but was still
131+
// present in the map. When that occurs, we replace the entry with our new valid entry, and return it,
132+
// guaranteeing this method will never return `null`.
133+
//
134+
// Note that this will not result in "leaks" of this value (even though such leaks would be harmless) as
135+
// the above case can only happen when the stored value was already considered weakly reachable - that is to
136+
// say it was already being GCed and no longer exists on the heap.
100137
map.put(key, ref);
101138
return t;
102139
} finally {
103140
Reference.reachabilityFence(t);
104141
}
105142
}
106143

107-
@SuppressWarnings("TypeParameterUnusedInFormals")
108-
public static <T> @Nullable T tryFind(final @NotNull Class<?> c, final @NotNull String key) {
144+
/**
145+
* Attempt to find the given object of the type {@code c} in the internment map by its string value, {@code key}.
146+
* The key for interned objects is always {@link TypeRepresentable#asInternal()}. Returns {@code null} if the given
147+
* key does not exist in the map.
148+
*
149+
* @param c The {@link Class} object of the type to check.
150+
* @param key The {@link TypeRepresentable#asInternal()} key of the value to check.
151+
* @return The currently interned value for the given key, if it exists, otherwise {@code null}.
152+
* @param <T> The type of the interned value.
153+
*/
154+
public static <T> @Nullable T tryFind(final @NotNull Class<T> c, final @NotNull String key) {
109155
final WeakReference<?> ref = internment.get(c).get(key);
110156
if (ref == null) {
111157
return null;
@@ -121,6 +167,12 @@ public final T intern() {
121167
}
122168
}
123169

170+
/**
171+
* Get the current estimated size of the internment map for the given class type.
172+
*
173+
* @param c The class to check.
174+
* @return The current estimated size of the internment map.
175+
*/
124176
public static long internmentSize(final @NotNull Class<?> c) {
125177
return internment.get(c).mappingCount();
126178
}

hypo-types/src/main/java/dev/denwav/hypo/types/PrimitiveType.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,94 @@
2525
import org.jetbrains.annotations.NotNull;
2626
import org.jetbrains.annotations.Nullable;
2727

28+
/**
29+
* Primitive types in Java, implementation for both {@link TypeDescriptor} and
30+
* {@link TypeSignature}.
31+
*
32+
* <p>There are 8 total primitive types in the JVM:
33+
* <table>
34+
* <caption>
35+
* Java Primitive Types
36+
* </caption>
37+
* <tr>
38+
* <th>Name</th>
39+
* <th>Wrapper Type</th>
40+
* <th>Internal Name</th>
41+
* </tr>
42+
* <tr>
43+
* <td>{@code char}</td>
44+
* <td>{@link java.lang.Character java/lang/Character}</td>
45+
* <td>{@code C}</td>
46+
* </tr>
47+
* <tr>
48+
* <td>{@code byte}</td>
49+
* <td>{@link java.lang.Byte java/lang/Byte}</td>
50+
* <td>{@code B}</td>
51+
* </tr>
52+
* <tr>
53+
* <td>{@code short}</td>
54+
* <td>{@link java.lang.Short java/lang/Short}</td>
55+
* <td>{@code S}</td>
56+
* </tr>
57+
* <tr>
58+
* <td>{@code int}</td>
59+
* <td>{@link java.lang.Integer java/lang/Integer}</td>
60+
* <td>{@code I}</td>
61+
* </tr>
62+
* <tr>
63+
* <td>{@code long}</td>
64+
* <td>{@link java.lang.Long java/lang/Long}</td>
65+
* <td>{@code J}</td>
66+
* </tr>
67+
* <tr>
68+
* <td>{@code float}</td>
69+
* <td>{@link java.lang.Float java/lang/Float}</td>
70+
* <td>{@code F}</td>
71+
* </tr>
72+
* <tr>
73+
* <td>{@code double}</td>
74+
* <td>{@link java.lang.Double java/lang/Double}</td>
75+
* <td>{@code D}</td>
76+
* </tr>
77+
* <tr>
78+
* <td>{@code boolean}</td>
79+
* <td>{@link java.lang.Boolean java/lang/Boolean}</td>
80+
* <td>{@code Z}</td>
81+
* </tr>
82+
* </table>
83+
*/
2884
public enum PrimitiveType implements TypeDescriptor, TypeSignature {
85+
/**
86+
* {@code char}
87+
*/
2988
CHAR("char", 'C', "java/lang/Character"),
89+
/**
90+
* {@code byte}
91+
*/
3092
BYTE("byte", 'B', "java/lang/Byte"),
93+
/**
94+
* {@code short}
95+
*/
3196
SHORT("short", 'S', "java/lang/Short"),
97+
/**
98+
* {@code int}
99+
*/
32100
INT("int", 'I', "java/lang/Integer"),
101+
/**
102+
* {@code long}
103+
*/
33104
LONG("long", 'J', "java/lang/Long"),
105+
/**
106+
* {@code float}
107+
*/
34108
FLOAT("float", 'F', "java/lang/Float"),
109+
/**
110+
* {@code double}
111+
*/
35112
DOUBLE("double", 'D', "java/lang/Double"),
113+
/**
114+
* {@code boolean}
115+
*/
36116
BOOLEAN("boolean", 'Z', "java/lang/Boolean"),
37117
;
38118

hypo-types/src/main/java/dev/denwav/hypo/types/TypeBindable.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,25 @@
2020

2121
import org.jetbrains.annotations.NotNull;
2222

23+
/**
24+
* A type which can be bound to a {@link dev.denwav.hypo.types.sig.param.TypeParameter TypeParameter}, or may contain
25+
* nested objects which themselves may satisfy that scenario. The intended pattern is for objects which fall in the
26+
* latter category to simply recursively call this method on all matching nested values.
27+
*
28+
* <p>Type variable binding only applies to {@link dev.denwav.hypo.types.sig.TypeSignature TypeSignature}-based types.
29+
*/
2330
public interface TypeBindable {
31+
32+
/**
33+
* Return a new instance of {@code this} (possibly as a different type) where all unbound type variables have been
34+
* bound to their associated type parameters using the provided {@code binder}. All valid type definitions must be
35+
* able to be bound, so failure to find a valid type parameter definition for an unbound type variable will result
36+
* in an {@link IllegalStateException}.
37+
*
38+
* @param binder The {@link TypeVariableBinder} to bind with.
39+
* @return A new instance of {@code this} (possibly as a different type) where all unbound type variables have been
40+
* bound to their associated type parameters
41+
* @throws IllegalStateException If a type variable could not be bound to an appropriate type parameter.
42+
*/
2443
@NotNull TypeBindable bind(final @NotNull TypeVariableBinder binder);
2544
}

hypo-types/src/main/java/dev/denwav/hypo/types/TypeRepresentable.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,24 @@
2020

2121
import org.jetbrains.annotations.NotNull;
2222

23+
/**
24+
* A value which represents a type in Java. "types" include 5 major categories:
25+
* <ul>
26+
* <li>{@link dev.denwav.hypo.types.desc.TypeDescriptor TypeDescriptor}</li>
27+
* <li>{@link dev.denwav.hypo.types.desc.MethodDescriptor MethodDescriptor}</li>
28+
* <li>{@link dev.denwav.hypo.types.sig.TypeSignature TypeSignature}</li>
29+
* <li>{@link dev.denwav.hypo.types.sig.MethodSignature MethodSignature}</li>
30+
* <li>{@link dev.denwav.hypo.types.sig.ClassSignature ClassSignature}</li>
31+
* </ul>
32+
*
33+
* <p>All types can be represented in two different ways, {@link #asReadable()}, and {@link #asInternal()}. Generally
34+
* "readable" will be in source code format, as would appear in a Java source file. Internal format matches exactly what
35+
* is present in compiled Java bytecode for the given type.
36+
*
37+
* <p>Implementations of this interface should have their {@link Object#toString() toString()} method defer to
38+
* {@link #asReadable()} to assist with debugging. {@link #asInternal()} should be used for serialization, as it matches
39+
* 1:1 with corresponding {@code parse()} methods for each type.
40+
*/
2341
public interface TypeRepresentable {
2442

2543
/**

hypo-types/src/main/java/dev/denwav/hypo/types/TypeVariableBinder.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,37 @@
2222
import org.jetbrains.annotations.NotNull;
2323
import org.jetbrains.annotations.Nullable;
2424

25+
/**
26+
* An object which provides bindings for {@link dev.denwav.hypo.types.sig.param.TypeVariable TypeVariables}. This is
27+
* generally as simple as finding the instance of {@link TypeParameter} which correspond with the given type variable
28+
* name.
29+
*
30+
* <p>Typical usage of this class is by passing it into the {@link TypeBindable#bind(TypeVariableBinder)} method. A
31+
* convenience method is also provided, {@link #bind(TypeBindable)}, which inverts that mechanism. This can make it
32+
* simpler when dealing with possibly {@code null} values.
33+
*/
2534
public interface TypeVariableBinder {
2635

36+
/**
37+
* A convenience method which inverts the typical order of the {@link TypeBindable#bind(TypeVariableBinder)} method
38+
* call. This can be used to safely call the bind method on possibly {@code null} objects.
39+
*
40+
* @param bindable The bindable object to pass this object into.
41+
* @return The result of calling {@link TypeBindable#bind(TypeVariableBinder)} if {@code bindable} is not null,
42+
* @param <T> The type of the bindable.
43+
*/
2744
default <T extends TypeBindable> @Nullable T bind(final @Nullable T bindable) {
2845
if (bindable == null) {
2946
return null;
3047
}
3148
return HypoTypesUtil.cast(bindable.bind(this));
3249
}
3350

51+
/**
52+
* Return the associated {@link TypeParameter} for the given variable name.
53+
*
54+
* @param name The variable name.
55+
* @return The associated {@link TypeParameter}, or {@code null} if not found.
56+
*/
3457
@Nullable TypeParameter bindingFor(final @NotNull String name);
3558
}

hypo-types/src/main/java/dev/denwav/hypo/types/VoidType.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,18 @@
2222
import dev.denwav.hypo.types.sig.TypeSignature;
2323
import org.jetbrains.annotations.NotNull;
2424

25+
/**
26+
* The {@code void} type in Java. This class is an implementation for both {@link TypeDescriptor} and
27+
* {@link TypeSignature}. {@code void} is only void when used as the return type in a method descriptor or signature, it
28+
* cannot be used as the type for any field or variable.
29+
*
30+
* <p>The wrapper type for {@code void} is {@link java.lang.Void java/lang/Void}. The internal name for {@code void} is
31+
* {@code V}.
32+
*/
2533
public enum VoidType implements TypeDescriptor, TypeSignature {
34+
/**
35+
* The singleton instance of this type object.
36+
*/
2637
INSTANCE,
2738
;
2839

hypo-types/src/main/java/dev/denwav/hypo/types/desc/ArrayTypeDescriptor.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,27 @@
2626
import java.util.concurrent.ConcurrentHashMap;
2727
import org.jetbrains.annotations.NotNull;
2828

29+
/**
30+
* A {@link TypeDescriptor} representing an array type. Array types consist of a {@link #getDimension() dimension} and a
31+
* {@link #getBaseType() base type}, which can be either a {@link dev.denwav.hypo.types.PrimitiveType PrimitiveType} or
32+
* a {@link ClassTypeDescriptor}.
33+
*
34+
* <p>Array type descriptors have the internal format of {@code [<base_type>}. The leading {@code [} is repeated to
35+
* denote the dimensionality of the array, so a 3-dimension array type would start with {@code [[[}.
36+
*/
2937
public final class ArrayTypeDescriptor extends Intern<ArrayTypeDescriptor> implements TypeDescriptor {
3038

3139
private final int dimension;
3240
private final @NotNull TypeDescriptor baseType;
3341

34-
public static @NotNull ArrayTypeDescriptor of(int dimension, @NotNull TypeDescriptor baseType) {
42+
/**
43+
* Create a {@link ArrayTypeDescriptor} instance.
44+
*
45+
* @param dimension The dimension for the new type.
46+
* @param baseType The base type for the new type.
47+
* @return The new {@link ArrayTypeDescriptor}.
48+
*/
49+
public static @NotNull ArrayTypeDescriptor of(final int dimension, final @NotNull TypeDescriptor baseType) {
3550
return new ArrayTypeDescriptor(dimension, baseType).intern();
3651
}
3752

@@ -68,10 +83,18 @@ public void asInternal(final @NotNull StringBuilder sb) {
6883
return ArrayTypeSignature.of(this.dimension, this.baseType.asSignature());
6984
}
7085

86+
/**
87+
* Get the dimension of this array type.
88+
* @return The dimension of this array type.
89+
*/
7190
public int getDimension() {
7291
return this.dimension;
7392
}
7493

94+
/**
95+
* Get the base type of this array type.
96+
* @return The base type of this array type.
97+
*/
7598
public @NotNull TypeDescriptor getBaseType() {
7699
return this.baseType;
77100
}

0 commit comments

Comments
 (0)