package xapi.collect.impl; import xapi.collect.X_Collect; import xapi.collect.api.CollectionOptions; import xapi.collect.api.IntTo; import xapi.collect.api.ObjectTo; import xapi.collect.proxy.CollectionProxy; import xapi.fu.In1; import xapi.fu.In2Out1; import xapi.fu.Out2; import xapi.fu.X_Fu; import xapi.util.impl.AbstractPair; import java.io.Serializable; import java.util.*; import java.util.Map.Entry; /** * @author James X. Nelson (james@wetheinter.net) * Created on 5/21/16. */ public class IntToSet <V> implements IntTo<V>, Serializable { private final CollectionProxy<Integer,V> store; private final CollectionOptions opts; private boolean needsRebalance; private final Object lock = new Object(); public <Generic extends V> IntToSet( Class<Generic> cls, CollectionOptions opts ) { opts = CollectionOptions.from(opts).forbidsDuplicate(true).build(); this.store = X_Collect.newProxy(Integer.class, cls, opts); this.opts = opts; } @Override public Iterable<V> forEach() { return store.iterateValues(); } @Override public int size() { return store.size(); } @Override public V[] toArray() { int s = size(); V[] values = newArray(s); final Iterator<V> itr = store.iterateValues().iterator(); for(int i = 0; i < s; i++) { values[i] = itr.next(); } return values; } private V[] newArray(int s) { V[] arr = X_Fu.<V>array(); arr = X_Fu.blank(arr, s); return arr; } @Override public boolean add(V item) { maybeRebalance(); assert valueType() == null || item == null || valueType().isAssignableFrom(item.getClass()); if (opts.forbidsDuplicate()) { if (contains(item)) { return false; } } return store.put(newEntry(size(), item)) == null; } @Override public boolean insert(int pos, V item) { maybeRebalance(); do { item = store.put(newEntry(pos++, item)); } while(item != null); return true; } protected Entry<Integer,V> newEntry(int size, V item) { return new AbstractPair<>(size, item); } public void push(V item) { maybeRebalance(); store.put(newEntry(size(), item)); } public V pop() { int size = size(); if (size > 0) { try { return get(--size); }finally { remove(size); } } return null; } @Override public Collection<V> toCollection(Collection<V> into) { if (into == null) { into = newList(); } Collection<V> target = into; forEachValue(v->target.add(v)); return into; } @Override public Map<Integer,V> toMap(Map<Integer,V> into) { if (into == null) { into = newMap(); } Map<Integer, V> target = into; forEachPair(target::put); return into; } protected Map<Integer, V> newMap() { return new LinkedHashMap<>(); } @Override public ObjectTo<Integer,V> clone(CollectionOptions options) { final ObjectTo<Integer, V> cloned = X_Collect.newMap(Integer.class, valueType(), options); forEachPair(cloned::put); return cloned; } @Override public boolean contains(V value) { if (value == null) { for (V val : forEach()) { if (val == null) { return true; } } } else { for (V val : forEach()) { if (value.equals(val)) { return true; } } } return false; } @Override public V at(int index) { maybeRebalance(); return store.get(index); } @Override public int indexOf(V value) { maybeRebalance(); if (value == null) { for (int i = 0, s = store.size(); i < s; i++) { if (store.get(i) == null) { return i; } } } else { for (int i = 0, s = store.size(); i < s; i++) { final V item = store.get(i); if (value.equals(item)) { return i; } } } return -1; } private void maybeRebalance() { if (needsRebalance) { if (opts.sparse()) { needsRebalance = false; return; } synchronized (lock) { if (needsRebalance) { needsRebalance = false; final V[] values = toArray(); clear(); addAll(values); } } } } @Override public boolean remove(int index) { if (store.remove(index) != null) { return (needsRebalance = true); } return false; } @Override public boolean findRemove(V value, boolean all) { boolean success = false; if (value == null) { for (Out2<Integer, V> o : store.forEachEntry()) { V val = o.out2(); if (val == null) { store.remove(o.out1()); needsRebalance = true; if (all) { success = true; } else { return true; } } } } else { for (Out2<Integer, V> o : store.forEachEntry()) { V val = o.out2(); if (value.equals(val)) { store.remove(o.out1()); needsRebalance = true; if (all) { success = true; } else { return true; } } } } return success; } @Override public void set(int index, V value) { maybeRebalance(); store.entryFor(index).setValue(value); } @Override public List<V> asList() { final List<V> list = newList(); maybeRebalance(); store.toCollection(list); return list; } protected List<V> newList() { return new ArrayList<>(); } @Override public Set<V> asSet() { final Set<V> set = newSet(); store.toCollection(set); return set; } protected Set<V> newSet() { return new LinkedHashSet<>(); } @Override public Deque<V> asDeque() { final Deque<V> deque = newDeque(); store.toCollection(deque); return deque; } protected Deque<V> newDeque() { return new ArrayDeque<>(); } @Override public V get(Object key) { return store.get(key); } public V put(int key, V value) { maybeRebalance(); Entry<Integer,V> entry = store.entryFor(key); V current = entry.getValue(); entry.setValue(value); return current; } @Override public V put(Entry<Integer,V> value) { maybeRebalance(); return store.put(value); } @Override public V remove(Object key) { needsRebalance = true; return store.remove(key); } @Override public boolean isEmpty() { return store.isEmpty(); } @Override public void clear() { store.clear(); needsRebalance = false; } @Override public Entry<Integer,V> entryFor(Object key) { maybeRebalance(); return store.entryFor(key); } @SuppressWarnings("unchecked") @Override public void setValue(Object key, Object value) { maybeRebalance(); if (key instanceof Number) { set(((Number)key).intValue(), (V)value); } else { assert false : "Cannot use .setValue on a non-Number key " + key; } } @Override public boolean addAll(Iterable<V> items) { boolean success = false; for (V item : items) { if (add(item)) { success = true; } } return success; } @Override @SuppressWarnings("unchecked") public boolean addAll(V ... items) { for (V item : items) { add(item); } return true; } public Class<Integer> keyType() { return Integer.class; } public Class<V> valueType() { return store.valueType(); } @Override public boolean readWhileTrue(In2Out1<Integer, V, Boolean> callback) { maybeRebalance(); for (int i = 0, m = size(); i < m; i++ ) { if (!callback.io(i, get(i))) { return false; } } return true; } @Override public String toString() { return toSource(); } @Override public boolean removeValue(V value) { return IntTo.super.removeValue(value); } @Override public void removeAll(In1<V> callback) { IntTo.super.removeAll(callback); } @Override public String toString(Integer key, V value) { return IntTo.super.toString(key, value); } }