334 lines
10 KiB
Java
334 lines
10 KiB
Java
|
package androidx.arch.core.internal;
|
||
|
|
||
|
import androidx.annotation.NonNull;
|
||
|
import androidx.annotation.RestrictTo;
|
||
|
import c.d.b.a.a;
|
||
|
import java.util.Iterator;
|
||
|
import java.util.Map;
|
||
|
import java.util.WeakHashMap;
|
||
|
@RestrictTo({RestrictTo.Scope.LIBRARY_GROUP_PREFIX})
|
||
|
public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {
|
||
|
private Entry<K, V> mEnd;
|
||
|
private WeakHashMap<SupportRemove<K, V>, Boolean> mIterators = new WeakHashMap<>();
|
||
|
private int mSize = 0;
|
||
|
public Entry<K, V> mStart;
|
||
|
|
||
|
public static class AscendingIterator<K, V> extends ListIterator<K, V> {
|
||
|
public AscendingIterator(Entry<K, V> entry, Entry<K, V> entry2) {
|
||
|
super(entry, entry2);
|
||
|
}
|
||
|
|
||
|
@Override // androidx.arch.core.internal.SafeIterableMap.ListIterator
|
||
|
public Entry<K, V> backward(Entry<K, V> entry) {
|
||
|
return entry.mPrevious;
|
||
|
}
|
||
|
|
||
|
@Override // androidx.arch.core.internal.SafeIterableMap.ListIterator
|
||
|
public Entry<K, V> forward(Entry<K, V> entry) {
|
||
|
return entry.mNext;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class DescendingIterator<K, V> extends ListIterator<K, V> {
|
||
|
public DescendingIterator(Entry<K, V> entry, Entry<K, V> entry2) {
|
||
|
super(entry, entry2);
|
||
|
}
|
||
|
|
||
|
@Override // androidx.arch.core.internal.SafeIterableMap.ListIterator
|
||
|
public Entry<K, V> backward(Entry<K, V> entry) {
|
||
|
return entry.mNext;
|
||
|
}
|
||
|
|
||
|
@Override // androidx.arch.core.internal.SafeIterableMap.ListIterator
|
||
|
public Entry<K, V> forward(Entry<K, V> entry) {
|
||
|
return entry.mPrevious;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static class Entry<K, V> implements Map.Entry<K, V> {
|
||
|
@NonNull
|
||
|
public final K mKey;
|
||
|
public Entry<K, V> mNext;
|
||
|
public Entry<K, V> mPrevious;
|
||
|
@NonNull
|
||
|
public final V mValue;
|
||
|
|
||
|
public Entry(@NonNull K k, @NonNull V v) {
|
||
|
this.mKey = k;
|
||
|
this.mValue = v;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Map.Entry, java.lang.Object
|
||
|
public boolean equals(Object obj) {
|
||
|
if (obj == this) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(obj instanceof Entry)) {
|
||
|
return false;
|
||
|
}
|
||
|
Entry entry = (Entry) obj;
|
||
|
return this.mKey.equals(entry.mKey) && this.mValue.equals(entry.mValue);
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Map.Entry
|
||
|
@NonNull
|
||
|
public K getKey() {
|
||
|
return this.mKey;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Map.Entry
|
||
|
@NonNull
|
||
|
public V getValue() {
|
||
|
return this.mValue;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Map.Entry, java.lang.Object
|
||
|
public int hashCode() {
|
||
|
return this.mKey.hashCode() ^ this.mValue.hashCode();
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Map.Entry
|
||
|
public V setValue(V v) {
|
||
|
throw new UnsupportedOperationException("An entry modification is not supported");
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Object
|
||
|
public String toString() {
|
||
|
return ((Object) this.mKey) + "=" + ((Object) this.mValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public class IteratorWithAdditions implements Iterator<Map.Entry<K, V>>, SupportRemove<K, V> {
|
||
|
private boolean mBeforeStart = true;
|
||
|
private Entry<K, V> mCurrent;
|
||
|
|
||
|
public IteratorWithAdditions() {
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public boolean hasNext() {
|
||
|
if (this.mBeforeStart) {
|
||
|
return SafeIterableMap.this.mStart != null;
|
||
|
}
|
||
|
Entry<K, V> entry = this.mCurrent;
|
||
|
return (entry == null || entry.mNext == null) ? false : true;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public Map.Entry<K, V> next() {
|
||
|
if (this.mBeforeStart) {
|
||
|
this.mBeforeStart = false;
|
||
|
this.mCurrent = SafeIterableMap.this.mStart;
|
||
|
} else {
|
||
|
Entry<K, V> entry = this.mCurrent;
|
||
|
this.mCurrent = entry != null ? entry.mNext : null;
|
||
|
}
|
||
|
return this.mCurrent;
|
||
|
}
|
||
|
|
||
|
@Override // androidx.arch.core.internal.SafeIterableMap.SupportRemove
|
||
|
public void supportRemove(@NonNull Entry<K, V> entry) {
|
||
|
Entry<K, V> entry2 = this.mCurrent;
|
||
|
if (entry == entry2) {
|
||
|
Entry<K, V> entry3 = entry2.mPrevious;
|
||
|
this.mCurrent = entry3;
|
||
|
this.mBeforeStart = entry3 == null;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static abstract class ListIterator<K, V> implements Iterator<Map.Entry<K, V>>, SupportRemove<K, V> {
|
||
|
public Entry<K, V> mExpectedEnd;
|
||
|
public Entry<K, V> mNext;
|
||
|
|
||
|
public ListIterator(Entry<K, V> entry, Entry<K, V> entry2) {
|
||
|
this.mExpectedEnd = entry2;
|
||
|
this.mNext = entry;
|
||
|
}
|
||
|
|
||
|
private Entry<K, V> nextNode() {
|
||
|
Entry<K, V> entry = this.mNext;
|
||
|
Entry<K, V> entry2 = this.mExpectedEnd;
|
||
|
if (entry == entry2 || entry2 == null) {
|
||
|
return null;
|
||
|
}
|
||
|
return forward(entry);
|
||
|
}
|
||
|
|
||
|
public abstract Entry<K, V> backward(Entry<K, V> entry);
|
||
|
|
||
|
public abstract Entry<K, V> forward(Entry<K, V> entry);
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public boolean hasNext() {
|
||
|
return this.mNext != null;
|
||
|
}
|
||
|
|
||
|
@Override // java.util.Iterator
|
||
|
public Map.Entry<K, V> next() {
|
||
|
Entry<K, V> entry = this.mNext;
|
||
|
this.mNext = nextNode();
|
||
|
return entry;
|
||
|
}
|
||
|
|
||
|
@Override // androidx.arch.core.internal.SafeIterableMap.SupportRemove
|
||
|
public void supportRemove(@NonNull Entry<K, V> entry) {
|
||
|
if (this.mExpectedEnd == entry && entry == this.mNext) {
|
||
|
this.mNext = null;
|
||
|
this.mExpectedEnd = null;
|
||
|
}
|
||
|
Entry<K, V> entry2 = this.mExpectedEnd;
|
||
|
if (entry2 == entry) {
|
||
|
this.mExpectedEnd = backward(entry2);
|
||
|
}
|
||
|
if (this.mNext == entry) {
|
||
|
this.mNext = nextNode();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public interface SupportRemove<K, V> {
|
||
|
void supportRemove(@NonNull Entry<K, V> entry);
|
||
|
}
|
||
|
|
||
|
public Iterator<Map.Entry<K, V>> descendingIterator() {
|
||
|
DescendingIterator descendingIterator = new DescendingIterator(this.mEnd, this.mStart);
|
||
|
this.mIterators.put(descendingIterator, Boolean.FALSE);
|
||
|
return descendingIterator;
|
||
|
}
|
||
|
|
||
|
public Map.Entry<K, V> eldest() {
|
||
|
return this.mStart;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Object
|
||
|
public boolean equals(Object obj) {
|
||
|
if (obj == this) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(obj instanceof SafeIterableMap)) {
|
||
|
return false;
|
||
|
}
|
||
|
SafeIterableMap safeIterableMap = (SafeIterableMap) obj;
|
||
|
if (size() != safeIterableMap.size()) {
|
||
|
return false;
|
||
|
}
|
||
|
Iterator<Map.Entry<K, V>> it = iterator();
|
||
|
Iterator<Map.Entry<K, V>> it2 = safeIterableMap.iterator();
|
||
|
while (it.hasNext() && it2.hasNext()) {
|
||
|
Map.Entry<K, V> next = it.next();
|
||
|
Map.Entry<K, V> next2 = it2.next();
|
||
|
if ((next == null && next2 != null) || (next != null && !next.equals(next2))) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return !it.hasNext() && !it2.hasNext();
|
||
|
}
|
||
|
|
||
|
public Entry<K, V> get(K k) {
|
||
|
Entry<K, V> entry = this.mStart;
|
||
|
while (entry != null && !entry.mKey.equals(k)) {
|
||
|
entry = entry.mNext;
|
||
|
}
|
||
|
return entry;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Object
|
||
|
public int hashCode() {
|
||
|
Iterator<Map.Entry<K, V>> it = iterator();
|
||
|
int i = 0;
|
||
|
while (it.hasNext()) {
|
||
|
i += it.next().hashCode();
|
||
|
}
|
||
|
return i;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Iterable
|
||
|
@NonNull
|
||
|
public Iterator<Map.Entry<K, V>> iterator() {
|
||
|
AscendingIterator ascendingIterator = new AscendingIterator(this.mStart, this.mEnd);
|
||
|
this.mIterators.put(ascendingIterator, Boolean.FALSE);
|
||
|
return ascendingIterator;
|
||
|
}
|
||
|
|
||
|
public SafeIterableMap<K, V>.IteratorWithAdditions iteratorWithAdditions() {
|
||
|
SafeIterableMap<K, V>.IteratorWithAdditions iteratorWithAdditions = new IteratorWithAdditions();
|
||
|
this.mIterators.put(iteratorWithAdditions, Boolean.FALSE);
|
||
|
return iteratorWithAdditions;
|
||
|
}
|
||
|
|
||
|
public Map.Entry<K, V> newest() {
|
||
|
return this.mEnd;
|
||
|
}
|
||
|
|
||
|
public Entry<K, V> put(@NonNull K k, @NonNull V v) {
|
||
|
Entry<K, V> entry = new Entry<>(k, v);
|
||
|
this.mSize++;
|
||
|
Entry<K, V> entry2 = this.mEnd;
|
||
|
if (entry2 == null) {
|
||
|
this.mStart = entry;
|
||
|
this.mEnd = entry;
|
||
|
return entry;
|
||
|
}
|
||
|
entry2.mNext = entry;
|
||
|
entry.mPrevious = entry2;
|
||
|
this.mEnd = entry;
|
||
|
return entry;
|
||
|
}
|
||
|
|
||
|
public V putIfAbsent(@NonNull K k, @NonNull V v) {
|
||
|
Entry<K, V> entry = get(k);
|
||
|
if (entry != null) {
|
||
|
return entry.mValue;
|
||
|
}
|
||
|
put(k, v);
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
public V remove(@NonNull K k) {
|
||
|
Entry<K, V> entry = get(k);
|
||
|
if (entry == null) {
|
||
|
return null;
|
||
|
}
|
||
|
this.mSize--;
|
||
|
if (!this.mIterators.isEmpty()) {
|
||
|
for (SupportRemove<K, V> supportRemove : this.mIterators.keySet()) {
|
||
|
supportRemove.supportRemove(entry);
|
||
|
}
|
||
|
}
|
||
|
Entry<K, V> entry2 = entry.mPrevious;
|
||
|
if (entry2 != null) {
|
||
|
entry2.mNext = entry.mNext;
|
||
|
} else {
|
||
|
this.mStart = entry.mNext;
|
||
|
}
|
||
|
Entry<K, V> entry3 = entry.mNext;
|
||
|
if (entry3 != null) {
|
||
|
entry3.mPrevious = entry2;
|
||
|
} else {
|
||
|
this.mEnd = entry2;
|
||
|
}
|
||
|
entry.mNext = null;
|
||
|
entry.mPrevious = null;
|
||
|
return entry.mValue;
|
||
|
}
|
||
|
|
||
|
public int size() {
|
||
|
return this.mSize;
|
||
|
}
|
||
|
|
||
|
@Override // java.lang.Object
|
||
|
public String toString() {
|
||
|
StringBuilder L = a.L("[");
|
||
|
Iterator<Map.Entry<K, V>> it = iterator();
|
||
|
while (it.hasNext()) {
|
||
|
L.append(it.next().toString());
|
||
|
if (it.hasNext()) {
|
||
|
L.append(", ");
|
||
|
}
|
||
|
}
|
||
|
L.append("]");
|
||
|
return L.toString();
|
||
|
}
|
||
|
}
|