|
|
@@ -1,590 +0,0 @@
|
|
|
-package net.ranides.assira.collection.prototype;
|
|
|
-
|
|
|
-import lombok.experimental.UtilityClass;
|
|
|
-import org.jetbrains.annotations.NotNull;
|
|
|
-import org.jetbrains.annotations.Nullable;
|
|
|
-
|
|
|
-import net.ranides.assira.collection.iterators.RemoveIterator;
|
|
|
-import net.ranides.assira.collection.maps.AEntry;
|
|
|
-import net.ranides.assira.collection.maps.AMap;
|
|
|
-import net.ranides.assira.collection.sets.SetUtils;
|
|
|
-import net.ranides.assira.reflection.*;
|
|
|
-
|
|
|
-import java.util.*;
|
|
|
-import java.util.function.Consumer;
|
|
|
-
|
|
|
-@UtilityClass
|
|
|
-public class AbstractPrototype {
|
|
|
-
|
|
|
- public static class DeclaredMap extends AbstractMap {
|
|
|
-
|
|
|
- private final PrototypeMap parent;
|
|
|
- private final Map<Object, Object> data;
|
|
|
-
|
|
|
- public DeclaredMap(PrototypeMap parent, Map<Object, Object> data) {
|
|
|
- this.parent = parent;
|
|
|
- this.data = data;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getParentMap() {
|
|
|
- return parent;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getDeclaredMap() {
|
|
|
- return this;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean containsKey(Object key) {
|
|
|
- return data.containsKey(key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object put(Object key, Object value) {
|
|
|
- return data.put(key, value);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object get(Object key) {
|
|
|
- return data.get(key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object remove(Object key) {
|
|
|
- return data.remove(key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return data.size();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean isEmpty() {
|
|
|
- return data.isEmpty();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean containsValue(Object value) {
|
|
|
- return data.containsValue(value);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void putAll(Map<?, ?> m) {
|
|
|
- data.putAll(m);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void clear() {
|
|
|
- data.clear();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Set<Object> keySet() {
|
|
|
- return data.keySet();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Collection<Object> values() {
|
|
|
- return data.values();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Set<Entry<Object, Object>> entrySet() {
|
|
|
- return data.entrySet();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int hashCode() {
|
|
|
- return data.hashCode();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean equals(Object other) {
|
|
|
- if(other instanceof DeclaredMap) {
|
|
|
- return data.equals(((DeclaredMap)other).data);
|
|
|
- }
|
|
|
- return super.equals(other);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public static class CompositeMap extends AbstractMap {
|
|
|
-
|
|
|
- private final PrototypeMap parent;
|
|
|
-
|
|
|
- private final DeclaredMap declared;
|
|
|
-
|
|
|
- private transient KeysView keys;
|
|
|
- private transient EntryView entries;
|
|
|
- private transient ValuesView values;
|
|
|
-
|
|
|
- protected CompositeMap(PrototypeMap parent, Map<Object, Object> content) {
|
|
|
- this.parent = parent;
|
|
|
- this.declared = new DeclaredMap(this, content);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getParentMap() {
|
|
|
- return parent;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getDeclaredMap() {
|
|
|
- return declared;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return keySet().size();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean isEmpty() {
|
|
|
- return declared.isEmpty() && (parent==null || parent.isEmpty());
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean containsKey(Object key) {
|
|
|
- return declared.containsKey(key) || (parent!=null && parent.containsKey(key));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean containsValue(Object value) {
|
|
|
- return declared.containsValue(value) || (parent!=null && parent.containsKey(value));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object get(Object key) {
|
|
|
- for(PrototypeMap scope = this; scope != null; scope = scope.getParentMap()) {
|
|
|
- Object out = scope.getDeclaredMap().get(key);
|
|
|
- if(out != null) {
|
|
|
- return out;
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- @Nullable
|
|
|
- @Override
|
|
|
- public Object put(Object key, Object value) {
|
|
|
- return declared.put(key, value);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object remove(Object key) {
|
|
|
- Object[] out = {null};
|
|
|
- forEachScope(scope -> {
|
|
|
- Object rem = scope.remove(key);
|
|
|
- if (rem != null && out[0] == null) {
|
|
|
- out[0] = rem;
|
|
|
- }
|
|
|
- });
|
|
|
- return out[0];
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void putAll(Map<?, ?> m) {
|
|
|
- declared.putAll(m);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void clear() {
|
|
|
- forEachScope(Map::clear);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Set<Object> keySet() {
|
|
|
- if (keys == null) {
|
|
|
- keys = new KeysView();
|
|
|
- }
|
|
|
- return keys;
|
|
|
- }
|
|
|
-
|
|
|
- @NotNull
|
|
|
- @Override
|
|
|
- public Collection<Object> values() {
|
|
|
- if (values == null) {
|
|
|
- values = new ValuesView();
|
|
|
- }
|
|
|
- return values;
|
|
|
- }
|
|
|
-
|
|
|
- @NotNull
|
|
|
- @Override
|
|
|
- public Set<Entry<Object, Object>> entrySet() {
|
|
|
- if (entries == null) {
|
|
|
- entries = new EntryView();
|
|
|
- }
|
|
|
- return entries;
|
|
|
- }
|
|
|
-
|
|
|
- protected void forEachScope(Consumer<PrototypeMap> consumer) {
|
|
|
- for(PrototypeMap scope = this; scope != null; scope = scope.getParentMap()) {
|
|
|
- consumer.accept(scope.getDeclaredMap());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private class EntryView extends AbstractSet<Entry<Object, Object>> {
|
|
|
- @Override
|
|
|
- public boolean contains(Object other) {
|
|
|
- if(other instanceof Entry<?,?>) {
|
|
|
- Entry<?,?> entry = (Entry<?,?>)other;
|
|
|
- return Objects.equals(declared.get(entry.getKey()), entry.getValue());
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean add(Entry<Object, Object> entry) {
|
|
|
- Object key = entry.getKey();
|
|
|
- Object val = entry.getValue();
|
|
|
-
|
|
|
- if(key instanceof PrototypeField<?>) {
|
|
|
- PrototypeField<?> field = (PrototypeField<?>) key;
|
|
|
- if(!field.type().isInstance(val)) {
|
|
|
- throw new ClassCastException(val + " can't be cast to " + field.type());
|
|
|
- }
|
|
|
- }
|
|
|
- declared.put(key, val);
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean remove(Object other) {
|
|
|
- if(other instanceof Entry<?,?>) {
|
|
|
- Entry<?,?> entry = (Entry<?,?>)other;
|
|
|
- return declared.remove(entry.getKey(), entry.getValue());
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void clear() {
|
|
|
- CompositeMap.this.clear();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Iterator<Entry<Object, Object>> iterator() {
|
|
|
- return new RemoveIterator<>(aggregate().iterator(), this::remove);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return aggregate().size();
|
|
|
- }
|
|
|
-
|
|
|
- public Set<Entry<Object, Object>> aggregate() {
|
|
|
- Set<Entry<Object, Object>> set = new HashSet<>();
|
|
|
- forEachScope(scope -> set.addAll(scope.entrySet()));
|
|
|
- return set;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private class ValuesView extends AbstractSet<Object> {
|
|
|
- @Override
|
|
|
- public boolean contains(Object other) {
|
|
|
- return CompositeMap.this.containsValue(other);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void clear() {
|
|
|
- CompositeMap.this.clear();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Iterator<Object> iterator() {
|
|
|
- return aggregate().iterator();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return aggregate().size();
|
|
|
- }
|
|
|
-
|
|
|
- public Collection<Object> aggregate() {
|
|
|
- if(parent == null) {
|
|
|
- return declared.values();
|
|
|
- }
|
|
|
- Set<Object> inserted = new HashSet<>();
|
|
|
- List<Object> list = new ArrayList<>();
|
|
|
- forEachScope(scope -> {
|
|
|
- scope.forEach((key, value) -> {
|
|
|
- if(inserted.add(key)) {
|
|
|
- list.add(value);
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
-
|
|
|
- return list;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private class KeysView extends AbstractSet<Object> {
|
|
|
- @Override
|
|
|
- public boolean contains(Object other) {
|
|
|
- return CompositeMap.this.containsKey(other);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public boolean remove(Object key) {
|
|
|
- return CompositeMap.this.remove(key) != null;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void clear() {
|
|
|
- CompositeMap.this.clear();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Iterator<Object> iterator() {
|
|
|
- return new RemoveIterator<>(aggregate().iterator(), this::remove);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public int size() {
|
|
|
- return aggregate().size();
|
|
|
- }
|
|
|
-
|
|
|
- public Set<Object> aggregate() {
|
|
|
- Set<Object> set = new HashSet<>();
|
|
|
- forEachScope(scope -> set.addAll(scope.keySet()));
|
|
|
- return set;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- @SuppressWarnings({"unchecked", "rawtypes"})
|
|
|
- private static abstract class AbstractMap extends AMap<Object, Object> implements PrototypeMap {
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Optional<PrototypeEntry<?>> getProperty(Object key) {
|
|
|
- if(containsKey(key)) {
|
|
|
- return Optional.of(PrototypeEntry.of(this, key));
|
|
|
- }
|
|
|
- return Optional.empty();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Optional<PrototypeEntry<Object>> getProperty(String key) {
|
|
|
- return (Optional)getProperty((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final <V> Optional<PrototypeEntry<V>> getProperty(PrototypeField<V> key) {
|
|
|
- return (Optional)getProperty((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Set<PrototypeEntry<?>> propertySet() {
|
|
|
- return SetUtils.map(keySet(), key -> PrototypeEntry.of(this, key));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final boolean containsKey(String key) {
|
|
|
- return containsKey((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final boolean containsKey(PrototypeField<?> key) {
|
|
|
- return containsKey((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Object put(String key, Object value) {
|
|
|
- return put((Object)key, value);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final <V> V put(PrototypeField<V> key, V value) {
|
|
|
- return (V)put((Object)key, value);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Object get(String key) {
|
|
|
- return get((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final <V> V get(PrototypeField<V> key) {
|
|
|
- return (V)get((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Optional<Object> getOptional(Object key) {
|
|
|
- return Optional.ofNullable(get(key));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Optional<Object> getOptional(String key) {
|
|
|
- return Optional.ofNullable(get(key));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final <V> Optional<V> getOptional(PrototypeField<V> key) {
|
|
|
- return Optional.ofNullable(get(key));
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final Object remove(String key) {
|
|
|
- return remove((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final <V> V remove(PrototypeField<V> key) {
|
|
|
- return (V)remove((Object)key);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- public static final class SimpleEntry<V> extends AEntry<Object, V> implements PrototypeEntry<V> {
|
|
|
- private final PrototypeMap scope;
|
|
|
- private final PrototypeField<V> field;
|
|
|
- private final IClass<V> type;
|
|
|
- private final String name;
|
|
|
- private final V value;
|
|
|
-
|
|
|
- public SimpleEntry(PrototypeMap scope, PrototypeField<V> field, V value) {
|
|
|
- this.scope = scope;
|
|
|
- this.field = field;
|
|
|
- this.type = field.type();
|
|
|
- this.name = field.name();
|
|
|
- this.value = value;
|
|
|
- }
|
|
|
-
|
|
|
- public SimpleEntry(PrototypeMap scope, IClass<V> type, String name, V value) {
|
|
|
- this.scope = scope;
|
|
|
- this.field = PrototypeField.of(type, name);
|
|
|
- this.type = field.type();
|
|
|
- this.name = field.name();
|
|
|
- this.value = value;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getScope() {
|
|
|
- return scope;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object getKey() {
|
|
|
- return field;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeField<V> getField() {
|
|
|
- return field;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public IClass<V> getType() {
|
|
|
- return type;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public String getName() {
|
|
|
- return name;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public V getValue() {
|
|
|
- return value;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public V setValue(V value) {
|
|
|
- throw new UnsupportedOperationException("SimpleEntry is immutable");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public static final class NameEntry extends AEntry<Object, Object> implements PrototypeEntry<Object> {
|
|
|
- private final PrototypeMap scope;
|
|
|
- private final String name;
|
|
|
-
|
|
|
- public NameEntry(PrototypeMap scope, String name) {
|
|
|
- this.scope = scope.getDeclaredMap();
|
|
|
- this.name = name;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getScope() {
|
|
|
- return scope;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeField<Object> getField() {
|
|
|
- return PrototypeField.of(name);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public IClass<Object> getType() {
|
|
|
- return IClass.OBJECT;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public String getName() {
|
|
|
- return name;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object getKey() {
|
|
|
- return name;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object getValue() {
|
|
|
- return scope.get(name);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object setValue(Object value) {
|
|
|
- return scope.put(name, value);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- public static final class FieldEntry<V> extends AEntry<Object, V> implements PrototypeEntry<V> {
|
|
|
- private final PrototypeMap scope;
|
|
|
- private final PrototypeField<V> field;
|
|
|
-
|
|
|
- public FieldEntry(PrototypeMap scope, PrototypeField<V> field) {
|
|
|
- this.scope = scope.getDeclaredMap();
|
|
|
- this.field = field;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeMap getScope() {
|
|
|
- return scope;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public PrototypeField<V> getField() {
|
|
|
- return field;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public IClass<V> getType() {
|
|
|
- return field.type();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public String getName() {
|
|
|
- return field.name();
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public Object getKey() {
|
|
|
- return field;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public V getValue() {
|
|
|
- return scope.get(field);
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public V setValue(V value) {
|
|
|
- return scope.put(field, value);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|