summaryrefslogtreecommitdiffstats
path: root/yolean/src/main/java/com/yahoo/yolean/chain/EnumeratedIdentitySet.java
diff options
context:
space:
mode:
Diffstat (limited to 'yolean/src/main/java/com/yahoo/yolean/chain/EnumeratedIdentitySet.java')
-rw-r--r--yolean/src/main/java/com/yahoo/yolean/chain/EnumeratedIdentitySet.java183
1 files changed, 183 insertions, 0 deletions
diff --git a/yolean/src/main/java/com/yahoo/yolean/chain/EnumeratedIdentitySet.java b/yolean/src/main/java/com/yahoo/yolean/chain/EnumeratedIdentitySet.java
new file mode 100644
index 00000000000..902391e7d24
--- /dev/null
+++ b/yolean/src/main/java/com/yahoo/yolean/chain/EnumeratedIdentitySet.java
@@ -0,0 +1,183 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.yolean.chain;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * A set using identity comparison.
+ * Keeps track of insertion order, which is available by calling insertionOrderedList.
+ *
+ * @author tonytv
+ */
+class EnumeratedIdentitySet<T> implements Set<T> {
+
+ private int counter = 0;
+ private final Map<T, Integer> set = new IdentityHashMap<>();
+
+ public EnumeratedIdentitySet(Collection<? extends T> collection) {
+ addAll(collection);
+ }
+
+ public EnumeratedIdentitySet() {
+ // empty
+ }
+
+ @Override
+ public int size() {
+ return set.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return set.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return set.containsKey(o);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return set.keySet().iterator();
+ }
+
+ @Override
+ public Object[] toArray() {
+ return set.keySet().toArray();
+ }
+
+ @Override
+ public <T1> T1[] toArray(T1[] a) {
+ return set.keySet().toArray(a);
+ }
+
+ @Override
+ public boolean add(T t) {
+ if (set.containsKey(t)) {
+ return false;
+ } else {
+ set.put(t, counter++);
+ return true;
+ }
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ return set.remove(o) != null;
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ return set.keySet().containsAll(c);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> collection) {
+ boolean changed = false;
+
+ for (T t : collection) {
+ changed |= add(t);
+ }
+
+ return changed;
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> collection) {
+ return set.keySet().retainAll(collection);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> collection) {
+ boolean changed = false;
+
+ for (Object o : collection) {
+ changed |= remove(o);
+ }
+
+ return changed;
+ }
+
+ @Override
+ public void clear() {
+ set.clear();
+ counter = 0;
+ }
+
+ public List<T> insertionOrderedList() {
+ if (set.isEmpty()) {
+ counter = 0;
+ return Collections.emptyList();
+ }
+
+ if (counter >= set.size() * 2 + 20) {
+ renumber();
+ }
+
+ return getKeysSortedByValue(set, counter);
+ }
+
+ private static <KEY> List<KEY> getKeysSortedByValue(Map<KEY, Integer> set, int maxValue) {
+ @SuppressWarnings("unchecked")
+ KEY[] result = (KEY[])Array.newInstance(headKey(set).getClass(), maxValue);
+
+ for (Map.Entry<KEY, Integer> entry : set.entrySet()) {
+ result[entry.getValue()] = entry.getKey();
+ }
+
+ return removeNulls(result);
+ }
+
+ private static <T> T headKey(Map<T, ?> map) {
+ return map.entrySet().iterator().next().getKey();
+ }
+
+ static <T> List<T> removeNulls(T[] list) {
+ int insertionSpot = 0;
+ for (int i = 0; i < list.length; i++) {
+ T element = list[i];
+ if (element != null) {
+ list[insertionSpot] = element;
+ insertionSpot++;
+ }
+ }
+ return Arrays.asList(list).subList(0, insertionSpot);
+ }
+
+ //only for testing
+ List<Integer> numbers() {
+ return new ArrayList<>(set.values());
+ }
+
+ private void renumber() {
+ SortedMap<Integer, T> invertedSet = invertedSortedMap(set);
+
+ int i = 0;
+ for (Map.Entry<Integer, T> entry : invertedSet.entrySet()) {
+ set.put(entry.getValue(), i++);
+ }
+ counter = i;
+ }
+
+ private static <K, V> SortedMap<V, K> invertedSortedMap(Map<K, V> map) {
+ SortedMap<V, K> result = new TreeMap<>();
+
+ for (Map.Entry<K, V> entry : map.entrySet()) {
+ result.put(entry.getValue(), entry.getKey());
+ }
+
+ return result;
+ }
+}