[utils] Who doesn't need some general util classes...

This commit is contained in:
2024-11-04 00:07:55 +01:00
parent 60aba0ee80
commit aaf05d1a33
8 changed files with 291 additions and 41 deletions

View File

@@ -1,224 +0,0 @@
package de.siphalor.tweed5.core.api.collection;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Array;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@SuppressWarnings("unchecked")
@RequiredArgsConstructor
public class TypedMultimap<T> implements Collection<T> {
private static final TypedMultimap<Object> EMPTY = unmodifiable(new TypedMultimap<>(Collections.emptyMap(), ArrayList::new));
protected final Map<Class<? extends T>, Collection<T>> delegate;
protected final Supplier<Collection<T>> collectionSupplier;
public static <T> TypedMultimap<T> unmodifiable(TypedMultimap<T> map) {
return new Unmodifiable<>(map.delegate, map.collectionSupplier);
}
public static <T> TypedMultimap<T> empty() {
return (TypedMultimap<T>) EMPTY;
}
public int size() {
return (int) delegate.values().stream().mapToLong(Collection::size).sum();
}
public boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(@NotNull Object o) {
return delegate.getOrDefault(o.getClass(), Collections.emptyList()).contains(o);
}
public Set<Class<? extends T>> classes() {
return delegate.keySet();
}
@Override
public @NotNull Iterator<T> iterator() {
return new Iterator<T>() {
private final Iterator<Map.Entry<Class<? extends T>, Collection<T>>> classIterator = delegate.entrySet().iterator();
private Iterator<? extends T> listIterator;
private boolean keptElement;
private boolean keptAnyElementInList;
@Override
public boolean hasNext() {
return classIterator.hasNext() || (listIterator != null && listIterator.hasNext());
}
@Override
public T next() {
if (keptElement) {
keptAnyElementInList = true;
}
if (listIterator == null || !listIterator.hasNext()) {
if (listIterator != null && !keptAnyElementInList) {
classIterator.remove();
}
listIterator = classIterator.next().getValue().iterator();
keptAnyElementInList = false;
}
keptElement = true;
return listIterator.next();
}
@Override
public void remove() {
if (listIterator == null) {
throw new IllegalStateException("Iterator has not been called");
}
keptElement = false;
listIterator.remove();
}
};
}
@Override
@NotNull
public Object @NotNull [] toArray() {
return delegate.values().stream().flatMap(Collection::stream).toArray();
}
@Override
@NotNull
public <S> S @NotNull [] toArray(@NotNull S @NotNull [] array) {
Class<?> clazz = array.getClass().getComponentType();
return delegate.values().stream()
.flatMap(Collection::stream)
.toArray(size -> (S[]) Array.newInstance(clazz, size));
}
@Override
public boolean add(@NotNull T value) {
return delegate.computeIfAbsent(((Class<T>) value.getClass()), clazz -> collectionSupplier.get()).add(value);
}
@Override
public boolean remove(@NotNull Object value) {
Collection<T> values = delegate.get(value.getClass());
if (values == null) {
return false;
}
if (values.remove(value)) {
if (values.isEmpty()) {
delegate.remove(value.getClass());
}
return true;
}
return false;
}
@NotNull
public <U extends T> Collection<U> getAll(Class<U> clazz) {
return (Collection<U>) Collections.unmodifiableCollection(delegate.getOrDefault(clazz, Collections.emptyList()));
}
@NotNull
public Collection<T> removeAll(Class<? extends T> clazz) {
Collection<T> removed = delegate.remove(clazz);
return removed == null ? Collections.emptyList() : Collections.unmodifiableCollection(removed);
}
@Override
public boolean containsAll(@NotNull Collection<?> values) {
for (Object value : values) {
if (!contains(value)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(@NotNull Collection<? extends T> values) {
boolean changed = false;
for (T value : values) {
changed = add(value) || changed;
}
return changed;
}
@Override
public boolean removeAll(@NotNull Collection<?> values) {
boolean changed = false;
for (Object value : values) {
changed = remove(value) || changed;
}
return changed;
}
@Override
public boolean retainAll(@NotNull Collection<?> values) {
Map<Class<?>, ? extends List<?>> valuesByClass = values.stream()
.collect(Collectors.groupingBy(Object::getClass));
delegate.putAll((Map<Class<? extends T>, List<T>>)(Object) valuesByClass);
delegate.keySet().removeIf(key -> !valuesByClass.containsKey(key));
return true;
}
@Override
public void clear() {
delegate.clear();
}
protected static class Unmodifiable<T> extends TypedMultimap<T> {
public Unmodifiable(
Map<Class<? extends T>, Collection<T>> delegate,
Supplier<Collection<T>> collectionSupplier
) {
super(delegate, collectionSupplier);
}
@Override
public @NotNull Iterator<T> iterator() {
return delegate.values().stream().flatMap(Collection::stream).iterator();
}
@Override
public boolean add(@NotNull T value) {
throw createUnsupportedOperationException();
}
@Override
public boolean remove(@NotNull Object value) {
throw createUnsupportedOperationException();
}
@Override
public @NotNull Collection<T> removeAll(Class<? extends T> clazz) {
throw createUnsupportedOperationException();
}
@Override
public boolean addAll(@NotNull Collection<? extends T> values) {
throw createUnsupportedOperationException();
}
@Override
public boolean removeAll(@NotNull Collection<?> values) {
throw createUnsupportedOperationException();
}
@Override
public boolean retainAll(@NotNull Collection<?> values) {
throw createUnsupportedOperationException();
}
@Override
public void clear() {
throw createUnsupportedOperationException();
}
protected UnsupportedOperationException createUnsupportedOperationException() {
return new UnsupportedOperationException("Map is unmodifiable");
}
}
}

View File

@@ -4,6 +4,7 @@ import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
import de.siphalor.tweed5.core.api.extension.TweedExtension;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Map;
@@ -15,10 +16,6 @@ import java.util.Map;
* @see ConfigContainerSetupPhase
*/
public interface ConfigContainer<T> {
ConfigContainerSetupPhase setupPhase();
default boolean isReady() {
return setupPhase() == ConfigContainerSetupPhase.READY;
}
default void registerExtensions(TweedExtension... extensions) {
for (TweedExtension extension : extensions) {
@@ -28,6 +25,10 @@ public interface ConfigContainer<T> {
void registerExtension(TweedExtension extension);
@Nullable
<E extends TweedExtension> E extension(Class<E> extensionClass);
Collection<TweedExtension> extensions();
void finishExtensionSetup();
void attachAndSealTree(ConfigEntry<T> rootEntry);
@@ -37,7 +38,5 @@ public interface ConfigContainer<T> {
void initialize();
ConfigEntry<T> rootEntry();
Collection<TweedExtension> extensions();
Map<Class<?>, ? extends RegisteredExtensionData<EntryExtensionsData, ?>> entryDataExtensions();
}

View File

@@ -9,33 +9,37 @@ import de.siphalor.tweed5.patchwork.api.PatchworkClassCreator;
import de.siphalor.tweed5.patchwork.impl.PatchworkClass;
import de.siphalor.tweed5.patchwork.impl.PatchworkClassGenerator;
import de.siphalor.tweed5.patchwork.impl.PatchworkClassPart;
import de.siphalor.tweed5.utils.api.collection.ClassToInstanceMap;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.Nullable;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
public class DefaultConfigContainer<T> implements ConfigContainer<T> {
@Getter
private ConfigContainerSetupPhase setupPhase = ConfigContainerSetupPhase.EXTENSIONS_SETUP;
private final Map<Class<? extends TweedExtension>, TweedExtension> extensions = new HashMap<>();
private final ClassToInstanceMap<TweedExtension> extensions = new ClassToInstanceMap<>();
private ConfigEntry<T> rootEntry;
private PatchworkClass<EntryExtensionsData> entryExtensionsDataPatchworkClass;
private Map<Class<?>, RegisteredExtensionDataImpl<EntryExtensionsData, ?>> registeredEntryDataExtensions;
@Override
public <E extends TweedExtension> @Nullable E extension(Class<E> extensionClass) {
return extensions.get(extensionClass);
}
@Override
public Collection<TweedExtension> extensions() {
return extensions.values();
return Collections.unmodifiableCollection(extensions.values());
}
@Override
public void registerExtension(TweedExtension extension) {
requireSetupPhase(ConfigContainerSetupPhase.EXTENSIONS_SETUP);
TweedExtension previous = extensions.put(extension.getClass(), extension);
TweedExtension previous = extensions.put(extension);
if (previous != null) {
throw new IllegalArgumentException("Extension " + extension.getClass().getName() + " is already registered");
}
@@ -65,7 +69,7 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
@Override
public void registerExtension(TweedExtension extension) {
if (!extensions.containsKey(extension.getClass())) {
if (!extensions.containsClass(extension.getClass())) {
additionalExtensions.add(extension);
}
}
@@ -78,7 +82,7 @@ public class DefaultConfigContainer<T> implements ConfigContainer<T> {
}
for (TweedExtension additionalExtension : additionalExtensions) {
extensions.put(additionalExtension.getClass(), additionalExtension);
extensions.put(additionalExtension);
}
extensionsToSetup = new ArrayList<>(additionalExtensions);
additionalExtensions.clear();