Skip to content

Commit 1df916c

Browse files
committed
Adds SupertypeList and various Comparator implementations.
Signed-off-by: Laird Nelson <[email protected]>
1 parent b8639ed commit 1df916c

File tree

7 files changed

+411
-52
lines changed

7 files changed

+411
-52
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
2+
*
3+
* Copyright © 2025 microBean™.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
11+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
*/
14+
package org.microbean.assign;
15+
16+
import java.util.Comparator;
17+
18+
import javax.lang.model.element.ElementKind;
19+
20+
/**
21+
* A {@link Comparator} establishing a <dfn>partial order</dfn> over {@link ElementKind}s such that {@linkplain
22+
* ElementKind#isClass() classes} precede {@linkplain ElementKind#isInterface() interfaces}.
23+
*
24+
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
25+
*
26+
* @see #compare(ElementKind, ElementKind)
27+
*/
28+
public final class ClassesThenInterfacesElementKindComparator implements Comparator<ElementKind> {
29+
30+
/**
31+
* The sole instance of this class.
32+
*/
33+
public static final ClassesThenInterfacesElementKindComparator INSTANCE = new ClassesThenInterfacesElementKindComparator();
34+
35+
private ClassesThenInterfacesElementKindComparator() {
36+
super();
37+
}
38+
39+
/**
40+
* Compares the two {@link ElementKind}s and returns the result.
41+
*
42+
* <p>If {@code k0 == k1}, returns {@code 0}.</p>
43+
*
44+
* <p>If {@code k0} is {@code null} and {@code k1} is not, returns a positive value.</p>
45+
*
46+
* <p>If {@code k0} {@linkplain ElementKind#isClass() is a class} and {@code k1} {@linkplain ElementKind#isInterface()
47+
* is an interface}, returns a negative value.</p>
48+
*
49+
* <p>If {@code k0} {@linkplain ElementKind#isInterface() is an interface} and {@code k1} {@linkplain
50+
* ElementKind#isClass() is a class}, returns a positive value.</p>
51+
*
52+
* <p>Returns {@code 0} in all other cases.
53+
*
54+
* @param k0 an {@link ElementKind}; may be {@code null}
55+
*
56+
* @param k1 an {@link ElementKind}; may be {@code null}
57+
*
58+
* @return a comparison result
59+
*
60+
* @see ElementKind#isClass()
61+
*
62+
* @see ElementKind#isInterface()
63+
*/
64+
@Override // Comparator<ElementKind>
65+
public final int compare(final ElementKind k0, final ElementKind k1) {
66+
if (k0 == k1) {
67+
return 0;
68+
} else if (k0 == null) {
69+
return 1;
70+
} else if (k1 == null) {
71+
return -1;
72+
} else if (k0.isClass() && k1.isInterface()) {
73+
return -1;
74+
} else if (k0.isInterface() && k1.isClass()) {
75+
return 1;
76+
} else {
77+
return 0;
78+
}
79+
}
80+
81+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
2+
*
3+
* Copyright © 2025 microBean™.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
11+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
*/
14+
package org.microbean.assign;
15+
16+
import java.util.Comparator;
17+
18+
import javax.lang.model.type.TypeKind;
19+
20+
/**
21+
* A {@link Comparator} establishing a <dfn>partial order</dfn> over {@link TypeKind}s such that {@linkplain
22+
* TypeKind#isPrimitive primitive types} precede {@linkplain TypeKind#DECLARED declared types}.
23+
*
24+
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
25+
*
26+
* @see #compare(TypeKind, TypeKind)
27+
*/
28+
public final class PrimitiveTypesThenDeclaredTypesTypeKindComparator implements Comparator<TypeKind> {
29+
30+
/**
31+
* The sole instance of this class.
32+
*/
33+
public static final PrimitiveTypesThenDeclaredTypesTypeKindComparator INSTANCE = new PrimitiveTypesThenDeclaredTypesTypeKindComparator();
34+
35+
private PrimitiveTypesThenDeclaredTypesTypeKindComparator() {
36+
super();
37+
}
38+
39+
/**
40+
* Compares the two {@link TypeKind}s and returns the result.
41+
*
42+
* <p>If {@code k0 == k1}, returns {@code 0}.</p>
43+
*
44+
* <p>If {@code k0} is {@code null} and {@code k1} is not, returns a positive value.</p>
45+
*
46+
* <p>If {@code k1} is {@code null} and {@code k0} is not, returns a negative value.</p>
47+
*
48+
* <p>If {@code k0} {@linkplain TypeKind#isPrimitive() is primitive} and {@code k1} is {@link TypeKind#DECLARED},
49+
* returns a negative value.</p>
50+
*
51+
* <p>If {@code k0} is {@link TypeKind#DECLARED} and {@code k1} {@linkplain TypeKind#isPrimitive() is primitive},
52+
* returns a positive value.</p>
53+
*
54+
* <p>Returns {@code 0} in all other cases.
55+
*
56+
* @param k0 a {@link TypeKind}; may be {@code null}
57+
*
58+
* @param k1 a {@link TypeKind}; may be {@code null}
59+
*
60+
* @return a comparison result
61+
*
62+
* @see TypeKind#isPrimitive()
63+
*
64+
* @see TypeKind#DECLARED
65+
*/
66+
@Override // Comparator<TypeKind>
67+
public final int compare(final TypeKind k0, final TypeKind k1) {
68+
if (k0 == k1) {
69+
return 0;
70+
} else if (k0 == null) {
71+
return 1;
72+
} else if (k1 == null) {
73+
return -1;
74+
} else if (k0.isPrimitive()) {
75+
return k1 == TypeKind.DECLARED ? -1 : 0;
76+
} else if (k0 == TypeKind.DECLARED) {
77+
return k1.isPrimitive() ? 1 : 0;
78+
} else {
79+
return 0;
80+
}
81+
}
82+
83+
}

src/main/java/org/microbean/assign/Qualifiers.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public static final List<NamedAttributeMap<?>> qualifiers(final Collection<? ext
199199
final ArrayList<NamedAttributeMap<?>> list = new ArrayList<>(c.size());
200200
for (final NamedAttributeMap<?> a : c) {
201201
if (qualifier(a)) {
202-
list.add(a);
202+
list.add(normalize(a));
203203
}
204204
}
205205
list.trimToSize();
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
2+
*
3+
* Copyright © 2025 microBean™.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
11+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
*/
14+
package org.microbean.assign;
15+
16+
import java.util.Comparator;
17+
import java.util.Objects;
18+
19+
import javax.lang.model.type.TypeMirror;
20+
21+
import org.microbean.construct.Domain;
22+
23+
/**
24+
* A {@link Comparator} of {@link TypeMirror}s that establishes a <dfn>partial order</dfn> on its arguments, enforcing
25+
* only that more specialized types precede less specialized ones.
26+
*
27+
* <strong>Instances of this class are (deliberately) not consistent with equals.</strong>
28+
*
29+
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
30+
*
31+
* @see #compare(TypeMirror, TypeMirror)
32+
*/
33+
public final class SpecializationComparator implements Comparator<TypeMirror> {
34+
35+
private final Domain domain;
36+
37+
/**
38+
* Creates a new {@link SpecializationComparator}.
39+
*
40+
* @param domain a {@link Domain}; must not be {@code null}
41+
*
42+
* @exception NullPointerException if {@code domain} is {@code null}
43+
*/
44+
public SpecializationComparator(final Domain domain) {
45+
super();
46+
this.domain = Objects.requireNonNull(domain, "domain");
47+
}
48+
49+
/**
50+
* Compares two {@link TypeMirror}s and returns the result.
51+
*
52+
* <p>The following rules are evaluated in order to calculate the returned result:</p>
53+
*
54+
* <p>If {@code t} {@code ==} {@code s}, or {@linkplain Domain#sameType(TypeMirror, TypeMirror) <code>t</code> and
55+
* <code>s</code> are the same time}, returns {@code 0}.</p>
56+
*
57+
* <p>If {@code t} is {@code null} and {@code s} is not, returns a positive value.</p>
58+
*
59+
* <p>If {@code s} is {@code null} and {@code t} is not, returns a negative value.</p>
60+
*
61+
* <p>If {@code t} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code s}, returns a negative
62+
* value.</p>
63+
*
64+
* <p>If {@code s} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code t}, returns a positive
65+
* value.</p>
66+
*
67+
* <p>In all other cases {@code 0} is returned.</p>.
68+
*
69+
* @param t a {@link TypeMirror}; may be {@code null}
70+
*
71+
* @param s a {@link TypeMirror}; may be {@code null}
72+
*
73+
* @return a comparison result
74+
*
75+
* @see Domain#sameType(TypeMirror, TypeMirror)
76+
*
77+
* @see Domain#subtype(TypeMirror, TypeMirror)
78+
*/
79+
@Override // Comparator<TypeMirror, TypeMirror>
80+
public final int compare(final TypeMirror t, final TypeMirror s) {
81+
if (t == s) {
82+
return 0;
83+
} else if (t == null) {
84+
return 1; // nulls right
85+
} else if (s == null) {
86+
return -1; // nulls right
87+
} else if (domain.sameType(t, s)) {
88+
return 0;
89+
} else if (domain.subtype(t, s)) {
90+
// t is a subtype of s; s is a proper supertype of t
91+
return -1;
92+
} else if (domain.subtype(s, t)) {
93+
// s is a subtype of t; t is a proper supertype of s
94+
return 1;
95+
} else {
96+
return 0;
97+
}
98+
}
99+
100+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
2+
*
3+
* Copyright © 2025 microBean™.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
6+
* the License. You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
11+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
12+
* specific language governing permissions and limitations under the License.
13+
*/
14+
package org.microbean.assign;
15+
16+
import java.util.AbstractList;
17+
import java.util.List;
18+
19+
import javax.lang.model.type.TypeMirror;
20+
21+
/**
22+
* An immutable {@link AbstractList} of {@link TypeMirror}s sorted in a specific way, intended to store the {@linkplain
23+
* Types#supertypes(TypeMirror) supertypes} of a {@link TypeMirror}.
24+
*
25+
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
26+
*
27+
* @see Types#supertypes(TypeMirror)
28+
*/
29+
public final class SupertypeList extends AbstractList<TypeMirror> {
30+
31+
private final List<TypeMirror> sortedSupertypes;
32+
33+
SupertypeList(final List<? extends TypeMirror> sortedSupertypes) {
34+
super();
35+
if (sortedSupertypes.isEmpty()) {
36+
throw new IllegalArgumentException();
37+
}
38+
switch (sortedSupertypes) {
39+
case SupertypeList sl -> this.sortedSupertypes = sl.sortedSupertypes;
40+
default -> this.sortedSupertypes = List.copyOf(sortedSupertypes);
41+
}
42+
}
43+
44+
@Override // AbstractList<TypeMirror>
45+
public final TypeMirror get(final int index) {
46+
return this.sortedSupertypes.get(index);
47+
}
48+
49+
@Override // AbstractList<TypeMirror>
50+
public final int size() {
51+
return this.sortedSupertypes.size();
52+
}
53+
54+
}

0 commit comments

Comments
 (0)