working on code
[bigint-presentation-code.git] / src / bigint_presentation_code / util.py
index 757f267ecdfabcc923980e3d863666b5c55d0305..4b7399fc83400ac7ea94bb5517251b5de7d5ce6f 100644 (file)
@@ -1,4 +1,5 @@
-from abc import abstractmethod
+from abc import ABCMeta, abstractmethod
+from functools import lru_cache
 from typing import (AbstractSet, Any, Iterable, Iterator, Mapping, MutableSet,
                     TypeVar, overload)
 
@@ -17,12 +18,42 @@ __all__ = [
     "OSet",
     "top_set_bit_index",
     "trailing_zero_count",
+    "InternedMeta",
 ]
 
 
-class OFSet(AbstractSet[_T_co]):
+class InternedMeta(ABCMeta):
+    def __init__(self, *args, **kwargs):
+        # type: (*Any, **Any) -> None
+        super().__init__(*args, **kwargs)
+        self.__INTERN_TABLE = {}  # type: dict[Any, Any]
+
+    def __intern(self, value):
+        # type: (_T) -> _T
+        value = self.__INTERN_TABLE.setdefault(value, value)
+        if value.__dict__.get("_InternedMeta__interned", False):
+            return value
+        value.__dict__["_InternedMeta__interned"] = True
+        hash_v = hash(value)
+        value.__dict__["__hash__"] = lambda: hash_v
+        old_eq = value.__eq__
+
+        def __eq__(__o):
+            # type: (_T) -> bool
+            if value.__class__ is __o.__class__:
+                return value is __o
+            return old_eq(__o)
+        value.__dict__["__eq__"] = __eq__
+        return value
+
+    def __call__(self, *args, **kwargs):
+        # type: (*Any, **Any) -> Any
+        return self.__intern(super().__call__(*args, **kwargs))
+
+
+class OFSet(AbstractSet[_T_co], metaclass=InternedMeta):
     """ ordered frozen set """
-    __slots__ = "__items",
+    __slots__ = "__items", "__dict__", "__weakref__"
 
     def __init__(self, items=()):
         # type: (Iterable[_T_co]) -> None
@@ -54,7 +85,7 @@ class OFSet(AbstractSet[_T_co]):
 
 class OSet(MutableSet[_T]):
     """ ordered mutable set """
-    __slots__ = "__items",
+    __slots__ = "__items", "__dict__"
 
     def __init__(self, items=()):
         # type: (Iterable[_T]) -> None
@@ -88,9 +119,9 @@ class OSet(MutableSet[_T]):
         return f"OSet({list(self)})"
 
 
-class FMap(Mapping[_T, _T_co]):
+class FMap(Mapping[_T, _T_co], metaclass=InternedMeta):
     """ordered frozen hashable mapping"""
-    __slots__ = "__items", "__hash"
+    __slots__ = "__items", "__hash", "__dict__", "__weakref__"
 
     @overload
     def __init__(self, items):
@@ -167,7 +198,7 @@ except AttributeError:
 
 
 class BaseBitSet(AbstractSet[int]):
-    __slots__ = "__bits",
+    __slots__ = "__bits", "__dict__", "__weakref__"
 
     @classmethod
     @abstractmethod
@@ -402,7 +433,7 @@ class BitSet(BaseBitSet, MutableSet[int]):
         return super().__isub__(it)
 
 
-class FBitSet(BaseBitSet):
+class FBitSet(BaseBitSet, metaclass=InternedMeta):
     """Frozen Bit Set"""
 
     @final