package com.google.android.agera;
import android.support.annotation.NonNull;
import java.util.Arrays;
final class IdentityMultimap<K, V> {
@NonNull
private static final Object[] NO_KEY_VALUES = new Object[0];
/**
* 用于存放 key 和 value
* 格式:
* index -> 0 1 2 3 4 5 6 7
* value -> key0 value0 key1 value1 key2 value2 key3 value4
*/
@NonNull
private Object[] keysValues = NO_KEY_VALUES;
/**
* 存放 key 和 value
*
* @param key key
* @param value value
* @return 是否存放成功
*/
synchronized boolean addKeyValuePair(@NonNull final K key, @NonNull final V value) {
int size = 0;
int indexToAdd = -1;
boolean hasValue = false;
/*
* 遍历存放的数据
* 判断是否要存放数据
*
* 如果 key 没有冲突,会寻找到一个可以添加 key 和 value 的位置
* 记录为 indexToAdd
* 然后结束循环,后进行 key 和 value 的存放工作
*/
for (int index = 0; index < keysValues.length; index += 2) {
final Object keysValue = keysValues[index];
/*
* 如果该位置的 key 为 null
* 表示可以添加
* 记录可添加的位置
*/
if (keysValue == null) {
indexToAdd = index;
}
/*
* 如果 key 冲突了
* 直接移到下一位置,就是该 key 的 value 位
* 判断 value 是否也冲突
* 如果冲突了 就表示 此次 存储 key value
* 不需要操作
* 记录为 hasValue = true
*/
if (keysValue == key) {
size++;
if (keysValues[index + 1] == value) {
indexToAdd = index;
hasValue = true;
}
}
}
/*
* 如果上面 没有找到了 可以添加的位置
* 进行数组 扩容( 就是 copy 原来 数组的数据,创建一个 新的数组 )
*
* 为什么扩容?
* 因为可能数组满了
*/
if (indexToAdd == -1) {
indexToAdd = keysValues.length;
keysValues = Arrays.copyOf(keysValues, indexToAdd < 2 ? 2 : indexToAdd * 2);
}
/*
* 如果 在上面 的 循环中没有发生冲突
* 代表没有存放过 value( 冲突的话,会在冲突 key 的后一位 存储 value 值 )
* 就是要同时存放 key 和 value
*/
if (!hasValue) {
keysValues[indexToAdd] = key;
keysValues[indexToAdd + 1] = value;
}
// 如果修改了,则返回 true
return size == 0;
}
/**
* 找到 对应 key 和 value
* 一定要两个一致
* 然后删除掉
*
* @param key key
* @param value value
*/
synchronized void removeKeyValuePair(@NonNull final K key, @NonNull final V value) {
for (int index = 0; index < keysValues.length; index += 2) {
if (keysValues[index] == key && keysValues[index + 1] == value) {
keysValues[index] = null;
keysValues[index + 1] = null;
}
}
}
/**
* 找到 对应 key
* 删除 该 key 和 key 对应的 value
*
* @param key key
* @return 是否删除成功
*/
synchronized boolean removeKey(@NonNull final K key) {
boolean removed = false;
for (int index = 0; index < keysValues.length; index += 2) {
if (keysValues[index] == key) {
keysValues[index] = null;
keysValues[index + 1] = null;
removed = true;
}
}
return removed;
}
}