Skip to content

Instantly share code, notes, and snippets.

@nithinivi
Last active August 9, 2024 04:19
Show Gist options
  • Select an option

  • Save nithinivi/6aaeb76bb88e9f9d512f2495ef827465 to your computer and use it in GitHub Desktop.

Select an option

Save nithinivi/6aaeb76bb88e9f9d512f2495ef827465 to your computer and use it in GitHub Desktop.
LookupTable
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.HashMap;
import java.io.Serializable;
import java.util.Collection;
import java.util.Set;
import java.util.Map;
import java.util.stream.Collectors;
public interface LookupTable<R, C, V> extends Serializable {
/**
* Returns {@code true} if the table contains a mapping with the specified row and column keys.
*
* @param rowKey key of row to search for
* @param columnKey key of column to search for
*/
boolean has(
R rowKey,
C columnKey);
/**
* Returns {@code true} if the table contains a mapping with the specified value.
*
* @param value value to search for
*/
boolean containsValue(V value);
V get(R rowKey, C columnKey);
/**
* Associates the specified value with the specified keys. If the table already contained a
* mapping for those keys, the old value is replaced with the specified value.
*
* @param rowKey row key that the value should be associated with
* @param columnKey column key that the value should be associated with
* @param value value to be associated with the specified keys
* @return the value previously associated with the keys, or {@code null} if no mapping existed
* for the keys
*/
V put(R rowKey, C columnKey, V value);
//
// /**
// * Copies all mappings from the specified table to this table. The effect is equivalent to calling
// * {@link #put} with each row key / column key / value mapping in {@code table}.
// *
// * @param table the table to add to this table
// */
// void putAll(Table<? extends R, ? extends C, ? extends V> table);
/**
* Removes all mappings from the table.
*/
V remove(R rowKey, C columnKey);
/**
* Returns a collection of all values, which may contain duplicates. Changes to the returned
* collection will update the underlying table, and vice versa.
*
* @return collection of values
*/
Collection<V> values();
/**
* Returns {@code true} if the table contains no mappings.
*/
boolean isEmpty();
/**
* Returns the number of row key / column key / value mappings in the table.
*/
int size();
/**
* Removes all mappings from the table.
*/
void clear();
/**
* Returns a Set of the row keys contained in this table.
*
* @return A Set view of the row keys contained in this table.
*/
Set<R> rowKeySet();
/**
* Returns a Set of the column keys contained in this table.
*
* @return A Set view of the column keys contained in this table.
*/
Set<C> columnKeySet();
}
class LookupHashTable<R, C, V> implements LookupTable<R, C, V> {
private final Map<R, Map<C, V>> table = new HashMap<>();
@Override
public boolean has(@NotNull R rowKey, @NotNull C columnKey) {
return table.containsKey(rowKey) && table.get(rowKey).containsKey(columnKey);
}
@Override
public boolean containsValue(@NotNull V value) {
return table.values().stream()
.flatMap(innerMap -> innerMap.values().stream())
.anyMatch(v -> v.equals(value));
}
@Override
public V get(@NotNull R rowKey, @NotNull C columnKey) {
return table.containsKey(rowKey)
? table.get(rowKey).get(columnKey)
: null;
}
@Override
public V put(@NotNull R rowKey, @NotNull C columnKey, @NotNull V value) {
if (table.containsKey(rowKey) && table.get(rowKey) != null) {
table.get(rowKey).put(columnKey, value);
} else {
var map = new HashMap<C, V>();
map.put(columnKey, value);
table.put(rowKey, map);
}
return table.get(rowKey).get(columnKey);
}
@Override
public V remove(@NotNull R rowKey, @NotNull C columnKey) {
if (!table.containsKey(rowKey))
return null;
if (!table.get(rowKey).containsKey(columnKey))
return null;
V removed;
removed = table.get(rowKey).remove(columnKey);
if (table.get(rowKey).isEmpty())
table.remove(rowKey);
return removed;
}
@Override
public Collection<V> values() {
return table.values().stream()
.flatMap(map -> map.values().stream())
.collect(Collectors.toList());
}
@Override
public boolean isEmpty() {
return table.isEmpty();
}
@Override
public int size() {
return table.values().stream()
.map(Map::size)
.reduce(0, Integer::sum);
}
@Override
public void clear() {
table.clear();
}
@Override
public Set<R> rowKeySet() {
return table.keySet();
}
@Override
public Set<C> columnKeySet() {
return table.values()
.stream().flatMap(map -> map.keySet().stream())
.collect(Collectors.toSet());
}
}
public class ConcurrentLookupTable<R, C, V> implements LookupTable<R, C, V> {
private final Map<R, Map<C, V>> table = new ConcurrentHashMap<>();
@Override
public boolean has(@NotNull R rowKey, @NotNull C columnKey) {
return table.containsKey(rowKey) && table.get(rowKey).containsKey(columnKey);
}
@Override
public boolean containsValue(@NotNull V value) {
return table.values().stream()
.flatMap(innerMap -> innerMap.values().stream())
.anyMatch(v -> v.equals(value));
}
@Override
public V get(@NotNull R rowKey, @NotNull C columnKey) {
return table.containsKey(rowKey)
? table.get(rowKey).get(columnKey)
: null;
}
@Override
public V put(@NotNull R rowKey, @NotNull C columnKey, @NotNull V value) {
if (table.containsKey(rowKey) && table.get(rowKey) != null) {
synchronized (table) {
table.get(rowKey).put(columnKey, value);
}
} else {
var map = new ConcurrentHashMap<C, V>();
map.put(columnKey, value);
synchronized (table) {
table.put(rowKey, map);
}
}
return table.get(rowKey).get(columnKey);
}
@Override
public V remove(@NotNull R rowKey,@NotNull C columnKey) {
if (!table.containsKey(rowKey))
return null;
if (!table.get(rowKey).containsKey(columnKey))
return null;
V removed;
synchronized (table) {
removed = table.get(rowKey).remove(columnKey);
if (table.get(rowKey).isEmpty())
table.remove(rowKey);
}
return removed;
}
@Override
public Collection<V> values() {
return table.values().stream()
.flatMap(map -> map.values().stream())
.collect(Collectors.toList());
}
@Override
public boolean isEmpty() {
return table.isEmpty();
}
@Override
public int size() {
return table.values().stream()
.map(Map::size)
.reduce(0, Integer::sum);
}
@Override
public void clear() {
table.clear();
}
@Override
public Set<R> rowKeySet() {
return table.keySet();
}
@Override
public Set<C> columnKeySet() {
return table.values()
.stream().flatMap(map -> map.keySet().stream())
.collect(Collectors.toSet());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment