*/
package org.opendaylight.mdsal.binding.generator.impl.rt;
+import static com.google.common.base.Verify.verify;
import static java.util.Objects.requireNonNull;
import com.google.common.base.Functions;
-import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
abstract class AbstractCompositeRuntimeType<S extends EffectiveStatement<?, ?>>
extends AbstractRuntimeType<S, GeneratedType> implements CompositeRuntimeType {
+ private static final RuntimeType[] EMPTY = new RuntimeType[0];
+
private final ImmutableMap<JavaTypeName, GeneratedRuntimeType> byClass;
- private final ImmutableMap<QName, RuntimeType> bySchemaTree;
+ private final Object bySchemaTree;
+ @SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE",
+ justification = "https://github.com/spotbugs/spotbugs/issues/1985")
AbstractCompositeRuntimeType(final GeneratedType bindingType, final S statement, final List<RuntimeType> children) {
super(bindingType, statement);
.map(GeneratedRuntimeType.class::cast)
.collect(ImmutableMap.toImmutableMap(GeneratedRuntimeType::getIdentifier, Functions.identity()));
- // Note: this may be over-sized, but we typically deal with schema tree statements, hence it is kind of accurate
- final var builder = ImmutableMap.<QName, RuntimeType>builderWithExpectedSize(children.size());
- for (var child : children) {
- final var stmt = child.statement();
- if (stmt instanceof SchemaTreeEffectiveStatement) {
- builder.put(((SchemaTreeEffectiveStatement<?>)stmt).argument(), child);
- }
+ final var tmp = children.stream()
+ .filter(child -> child.statement() instanceof SchemaTreeEffectiveStatement)
+ .toArray(RuntimeType[]::new);
+ switch (tmp.length) {
+ case 0:
+ bySchemaTree = EMPTY;
+ break;
+ case 1:
+ bySchemaTree = tmp[0];
+ break;
+ default:
+ Arrays.sort(tmp, (o1, o2) -> {
+ final int cmp = extractQName(o1).compareTo(extractQName(o2));
+ verify(cmp != 0, "Type %s conflicts with %s on schema tree", o1, o2);
+ return cmp;
+ });
+ bySchemaTree = tmp;
}
- bySchemaTree = builder.build();
}
@Override
public final RuntimeType schemaTreeChild(final QName qname) {
- return bySchemaTree.get(requireNonNull(qname));
+ if (bySchemaTree instanceof RuntimeType) {
+ final var tmp = (RuntimeType) bySchemaTree;
+ return qname.equals(tmp.statement().argument()) ? tmp : null;
+ }
+
+ final var tmp = (RuntimeType[]) bySchemaTree;
+ @SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE",
+ justification = "https://github.com/spotbugs/spotbugs/issues/1985")
+ final int offset = Arrays.binarySearch(tmp, null, (o1, o2) -> {
+ // We make assumptions about how Arrays.binarySearch() is implemented: o2 is expected to be the provided
+ // key -- which is null. This helps CHA by not introducing a fake RuntimeType class and the
+ // corresponding instanceof checks.
+ verify(o2 == null, "Unexpected key %s", o2);
+ return extractQName(o1).compareTo(qname);
+ });
+ return offset < 0 ? null : tmp[offset];
}
@Override
return byClass.get(requireNonNull(typeName));
}
- final @NonNull ImmutableCollection<RuntimeType> schemaTreeChildren() {
- return bySchemaTree.values();
+ // Makes an assertion of all types being of specified type
+ @SuppressWarnings("unchecked")
+ final <T extends RuntimeType> @NonNull List<T> schemaTree(final Class<T> expectedType) {
+ if (expectedType.isInstance(bySchemaTree)) {
+ return List.of(expectedType.cast(bySchemaTree));
+ }
+
+ final var tmp = (RuntimeType[]) bySchemaTree;
+ for (var item : tmp) {
+ verify(expectedType.isInstance(item), "Unexpected schema tree child %s", item);
+ }
+ return (List<T>) Collections.unmodifiableList(Arrays.asList(tmp));
+ }
+
+ private static @NonNull QName extractQName(final RuntimeType type) {
+ final var stmt = type.statement();
+ verify(stmt instanceof SchemaTreeEffectiveStatement, "Unexpected statement %s in %s", stmt, type);
+ return ((SchemaTreeEffectiveStatement<?>) stmt).argument();
}
-}
+}
\ No newline at end of file