merge
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
from typing import Generic, TypeVar
|
||||
|
||||
Key = TypeVar("Key")
|
||||
Value = TypeVar("Value")
|
||||
|
||||
|
||||
class TwoWayDict(Generic[Key, Value]):
|
||||
"""
|
||||
A two-way mapping offering O(1) access in both directions.
|
||||
|
||||
Wraps two dictionaries and uses them to provide efficient access to
|
||||
both values (given keys) and keys (given values).
|
||||
"""
|
||||
|
||||
def __init__(self, initial: dict[Key, Value] | None = None) -> None:
|
||||
initial_data = {} if initial is None else initial
|
||||
self._forward: dict[Key, Value] = initial_data
|
||||
self._reverse: dict[Value, Key] = {value: key for key, value in initial_data.items()}
|
||||
self._lock = threading.RLock()
|
||||
|
||||
def __setitem__(self, key: Key, value: Value) -> None:
|
||||
with self._lock:
|
||||
# If reassigning the same key, remove old reverse mapping first
|
||||
old_value = self._forward.get(key)
|
||||
if old_value is not None and old_value != value:
|
||||
del self._reverse[old_value]
|
||||
# Enforce 1:1 mapping: value must not already map to a different key
|
||||
existing_key = self._reverse.get(value)
|
||||
if existing_key is not None and existing_key != key:
|
||||
raise ValueError(f"Value {value!r} already mapped to key {existing_key!r}")
|
||||
self._forward[key] = value
|
||||
self._reverse[value] = key
|
||||
|
||||
def __delitem__(self, key: Key) -> None:
|
||||
with self._lock:
|
||||
value = self._forward[key]
|
||||
self._forward.__delitem__(key)
|
||||
self._reverse.__delitem__(value)
|
||||
|
||||
def __iter__(self):
|
||||
with self._lock:
|
||||
return iter(dict(self._forward))
|
||||
|
||||
def get(self, key: Key) -> Value | None:
|
||||
"""Given a key, efficiently lookup and return the associated value.
|
||||
|
||||
Args:
|
||||
key: The key
|
||||
|
||||
Returns:
|
||||
The value
|
||||
"""
|
||||
with self._lock:
|
||||
return self._forward.get(key)
|
||||
|
||||
def get_key(self, value: Value) -> Key | None:
|
||||
"""Given a value, efficiently lookup and return the associated key.
|
||||
|
||||
Args:
|
||||
value: The value
|
||||
|
||||
Returns:
|
||||
The key
|
||||
"""
|
||||
with self._lock:
|
||||
return self._reverse.get(value)
|
||||
|
||||
def contains_value(self, value: Value) -> bool:
|
||||
"""Check if `value` is a value within this TwoWayDict.
|
||||
|
||||
Args:
|
||||
value: The value to check.
|
||||
|
||||
Returns:
|
||||
True if the value is within the values of this dict.
|
||||
"""
|
||||
with self._lock:
|
||||
return value in self._reverse
|
||||
|
||||
def __len__(self):
|
||||
with self._lock:
|
||||
return len(self._forward)
|
||||
|
||||
def __contains__(self, item: Key) -> bool:
|
||||
with self._lock:
|
||||
return item in self._forward
|
||||
Reference in New Issue
Block a user