Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2025 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.microbean.assign;

import java.util.Comparator;

import javax.lang.model.element.ElementKind;

/**
* A {@link Comparator} establishing a <dfn>partial order</dfn> over {@link ElementKind}s such that {@linkplain
* ElementKind#isClass() classes} precede {@linkplain ElementKind#isInterface() interfaces}.
*
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
*
* @see #compare(ElementKind, ElementKind)
*/
public final class ClassesThenInterfacesElementKindComparator implements Comparator<ElementKind> {

/**
* The sole instance of this class.
*/
public static final ClassesThenInterfacesElementKindComparator INSTANCE = new ClassesThenInterfacesElementKindComparator();

private ClassesThenInterfacesElementKindComparator() {
super();
}

/**
* Compares the two {@link ElementKind}s and returns the result.
*
* <p>If {@code k0 == k1}, returns {@code 0}.</p>
*
* <p>If {@code k0} is {@code null} and {@code k1} is not, returns a positive value.</p>
*
* <p>If {@code k0} {@linkplain ElementKind#isClass() is a class} and {@code k1} {@linkplain ElementKind#isInterface()
* is an interface}, returns a negative value.</p>
*
* <p>If {@code k0} {@linkplain ElementKind#isInterface() is an interface} and {@code k1} {@linkplain
* ElementKind#isClass() is a class}, returns a positive value.</p>
*
* <p>Returns {@code 0} in all other cases.
*
* @param k0 an {@link ElementKind}; may be {@code null}
*
* @param k1 an {@link ElementKind}; may be {@code null}
*
* @return a comparison result
*
* @see ElementKind#isClass()
*
* @see ElementKind#isInterface()
*/
@Override // Comparator<ElementKind>
public final int compare(final ElementKind k0, final ElementKind k1) {
if (k0 == k1) {
return 0;
} else if (k0 == null) {
return 1;
} else if (k1 == null) {
return -1;
} else if (k0.isClass() && k1.isInterface()) {
return -1;
} else if (k0.isInterface() && k1.isClass()) {
return 1;
} else {
return 0;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2025 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.microbean.assign;

import java.util.Comparator;

import javax.lang.model.type.TypeKind;

/**
* A {@link Comparator} establishing a <dfn>partial order</dfn> over {@link TypeKind}s such that {@linkplain
* TypeKind#isPrimitive primitive types} precede {@linkplain TypeKind#DECLARED declared types}.
*
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
*
* @see #compare(TypeKind, TypeKind)
*/
public final class PrimitiveTypesThenDeclaredTypesTypeKindComparator implements Comparator<TypeKind> {

/**
* The sole instance of this class.
*/
public static final PrimitiveTypesThenDeclaredTypesTypeKindComparator INSTANCE = new PrimitiveTypesThenDeclaredTypesTypeKindComparator();

private PrimitiveTypesThenDeclaredTypesTypeKindComparator() {
super();
}

/**
* Compares the two {@link TypeKind}s and returns the result.
*
* <p>If {@code k0 == k1}, returns {@code 0}.</p>
*
* <p>If {@code k0} is {@code null} and {@code k1} is not, returns a positive value.</p>
*
* <p>If {@code k1} is {@code null} and {@code k0} is not, returns a negative value.</p>
*
* <p>If {@code k0} {@linkplain TypeKind#isPrimitive() is primitive} and {@code k1} is {@link TypeKind#DECLARED},
* returns a negative value.</p>
*
* <p>If {@code k0} is {@link TypeKind#DECLARED} and {@code k1} {@linkplain TypeKind#isPrimitive() is primitive},
* returns a positive value.</p>
*
* <p>Returns {@code 0} in all other cases.
*
* @param k0 a {@link TypeKind}; may be {@code null}
*
* @param k1 a {@link TypeKind}; may be {@code null}
*
* @return a comparison result
*
* @see TypeKind#isPrimitive()
*
* @see TypeKind#DECLARED
*/
@Override // Comparator<TypeKind>
public final int compare(final TypeKind k0, final TypeKind k1) {
if (k0 == k1) {
return 0;
} else if (k0 == null) {
return 1;
} else if (k1 == null) {
return -1;
} else if (k0.isPrimitive()) {
return k1 == TypeKind.DECLARED ? -1 : 0;
} else if (k0 == TypeKind.DECLARED) {
return k1.isPrimitive() ? 1 : 0;
} else {
return 0;
}
}

}
2 changes: 1 addition & 1 deletion src/main/java/org/microbean/assign/Qualifiers.java
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public static final List<NamedAttributeMap<?>> qualifiers(final Collection<? ext
final ArrayList<NamedAttributeMap<?>> list = new ArrayList<>(c.size());
for (final NamedAttributeMap<?> a : c) {
if (qualifier(a)) {
list.add(a);
list.add(normalize(a));
}
}
list.trimToSize();
Expand Down
100 changes: 100 additions & 0 deletions src/main/java/org/microbean/assign/SpecializationComparator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2025 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.microbean.assign;

import java.util.Comparator;
import java.util.Objects;

import javax.lang.model.type.TypeMirror;

import org.microbean.construct.Domain;

/**
* A {@link Comparator} of {@link TypeMirror}s that establishes a <dfn>partial order</dfn> on its arguments, enforcing
* only that more specialized types precede less specialized ones.
*
* <strong>Instances of this class are (deliberately) not consistent with equals.</strong>
*
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
*
* @see #compare(TypeMirror, TypeMirror)
*/
public final class SpecializationComparator implements Comparator<TypeMirror> {

private final Domain domain;

/**
* Creates a new {@link SpecializationComparator}.
*
* @param domain a {@link Domain}; must not be {@code null}
*
* @exception NullPointerException if {@code domain} is {@code null}
*/
public SpecializationComparator(final Domain domain) {
super();
this.domain = Objects.requireNonNull(domain, "domain");
}

/**
* Compares two {@link TypeMirror}s and returns the result.
*
* <p>The following rules are evaluated in order to calculate the returned result:</p>
*
* <p>If {@code t} {@code ==} {@code s}, or {@linkplain Domain#sameType(TypeMirror, TypeMirror) <code>t</code> and
* <code>s</code> are the same time}, returns {@code 0}.</p>
*
* <p>If {@code t} is {@code null} and {@code s} is not, returns a positive value.</p>
*
* <p>If {@code s} is {@code null} and {@code t} is not, returns a negative value.</p>
*
* <p>If {@code t} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code s}, returns a negative
* value.</p>
*
* <p>If {@code s} {@linkplain Domain#subtype(TypeMirror, TypeMirror) is a subtype of} {@code t}, returns a positive
* value.</p>
*
* <p>In all other cases {@code 0} is returned.</p>.
*
* @param t a {@link TypeMirror}; may be {@code null}
*
* @param s a {@link TypeMirror}; may be {@code null}
*
* @return a comparison result
*
* @see Domain#sameType(TypeMirror, TypeMirror)
*
* @see Domain#subtype(TypeMirror, TypeMirror)
*/
@Override // Comparator<TypeMirror, TypeMirror>
public final int compare(final TypeMirror t, final TypeMirror s) {
if (t == s) {
return 0;
} else if (t == null) {
return 1; // nulls right
} else if (s == null) {
return -1; // nulls right
} else if (domain.sameType(t, s)) {
return 0;
} else if (domain.subtype(t, s)) {
// t is a subtype of s; s is a proper supertype of t
return -1;
} else if (domain.subtype(s, t)) {
// s is a subtype of t; t is a proper supertype of s
return 1;
} else {
return 0;
}
}

}
54 changes: 54 additions & 0 deletions src/main/java/org/microbean/assign/SupertypeList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
*
* Copyright © 2025 microBean™.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.microbean.assign;

import java.util.AbstractList;
import java.util.List;

import javax.lang.model.type.TypeMirror;

/**
* An immutable {@link AbstractList} of {@link TypeMirror}s sorted in a specific way, intended to store the {@linkplain
* Types#supertypes(TypeMirror) supertypes} of a {@link TypeMirror}.
*
* @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a>
*
* @see Types#supertypes(TypeMirror)
*/
public final class SupertypeList extends AbstractList<TypeMirror> {

private final List<TypeMirror> sortedSupertypes;

SupertypeList(final List<? extends TypeMirror> sortedSupertypes) {
super();
if (sortedSupertypes.isEmpty()) {
throw new IllegalArgumentException();
}
switch (sortedSupertypes) {
case SupertypeList sl -> this.sortedSupertypes = sl.sortedSupertypes;
default -> this.sortedSupertypes = List.copyOf(sortedSupertypes);
}
}

@Override // AbstractList<TypeMirror>
public final TypeMirror get(final int index) {
return this.sortedSupertypes.get(index);
}

@Override // AbstractList<TypeMirror>
public final int size() {
return this.sortedSupertypes.size();
}

}
Loading
Loading