'''simple docstring'''

from __future__ import annotations

from collections.abc import Callable
from typing import Generic, TypeVar

lowerCAmelCase_			:			Union[str, Any]    	=   TypeVar("T")
lowerCAmelCase_			:			Tuple    	=   TypeVar("U")





class 				lowercase    (    Generic[T, U]			):


   def __init__( self					:						List[str] ,		__lowerCAmelCase					:						T | None ,		__lowerCAmelCase					:						U | None)   ->       List[str]:
         lowercase_     			=   key
         lowercase_     			=   val
         lowercase_     			=   0
         lowercase_     			=   None
         lowercase_     			=   None


   def __repr__( self					:						Any)   ->       str:
         return "Node: key: {}, val: {}, freq: {}, has next: {}, has prev: {}".format(
             self.key ,		self.val ,		self.freq ,		self.next is not None ,		self.prev is not None)





class 				lowercase    (    Generic[T, U]			):


   def __init__( self					:						Optional[Any])   ->       None:
         lowercase_     			=   DoubleLinkedListNode(__lowerCAmelCase ,		__lowerCAmelCase)
         lowercase_     			=   DoubleLinkedListNode(__lowerCAmelCase ,		__lowerCAmelCase)
         lowercase_			,				lowercase_     			=   self.rear, self.head


   def __repr__( self					:						List[str])   ->       str:
         lowercase_     			=   ["DoubleLinkedList"]
         lowercase_     			=   self.head
         while node.next is not None:
               rep.append(str(__lowerCAmelCase))
               lowercase_     			=   node.next
         rep.append(str(self.rear))
         return ",\n    ".join(__lowerCAmelCase)


   def __UpperCAmelCase							( self					:						int ,		__lowerCAmelCase					:						DoubleLinkedListNode[T, U])   ->       None:
         lowercase_     			=   self.rear.prev

         # All nodes other than self.head are guaranteed to have non-None previous
         assert previous is not None

         lowercase_     			=   node
         lowercase_     			=   previous
         lowercase_     			=   node
         lowercase_     			=   self.rear
         node.freq += 1
         self._position_node(__lowerCAmelCase)


   def __UpperCAmelCase							( self					:						List[Any] ,		__lowerCAmelCase					:						DoubleLinkedListNode[T, U])   ->       None:

         while node.prev is not None and node.prev.freq > node.freq:
               # swap node with previous node
               lowercase_     			=   node.prev

               lowercase_     			=   previous_node.prev
               lowercase_     			=   node.prev
               lowercase_     			=   previous_node
               lowercase_     			=   node


   def __UpperCAmelCase							( self					:						Union[str, Any] ,		__lowerCAmelCase					:						DoubleLinkedListNode[T, U])   ->       DoubleLinkedListNode[T, U] | None:

         if node.prev is None or node.next is None:
               return None

         lowercase_     			=   node.next
         lowercase_     			=   node.prev
         lowercase_     			=   None
         lowercase_     			=   None
         return node





class 				lowercase    (    Generic[T, U]			):
   lowerCamelCase_            ={}


   def __init__( self					:						Optional[Any] ,		__lowerCAmelCase					:						int)   ->       str:
         lowercase_     			=   DoubleLinkedList()
         lowercase_     			=   capacity
         lowercase_     			=   0
         lowercase_     			=   0
         lowercase_     			=   0
         lowercase_     			=   {}


   def __repr__( self					:						List[str])   ->       str:
         return (
             F'CacheInfo(hits={self.hits}, misses={self.miss}, '
             F'capacity={self.capacity}, current_size={self.num_keys})'
         )


   def __contains__( self					:						Optional[Any] ,		__lowerCAmelCase					:						T)   ->       bool:
         return key in self.cache


   def __UpperCAmelCase							( self					:						Tuple ,		__lowerCAmelCase					:						T)   ->       U | None:

         if key in self.cache:
               self.hits += 1
               lowercase_     			=   self.cache[key]
               lowercase_     			=   self.list.remove(self.cache[key])
               assert node == value_node

               # node is guaranteed not None because it is in self.cache
               assert node is not None
               self.list.add(__lowerCAmelCase)
               return node.val
         self.miss += 1
         return None


   def __UpperCAmelCase							( self					:						Union[str, Any] ,		__lowerCAmelCase					:						T ,		__lowerCAmelCase					:						U)   ->       None:

         if key not in self.cache:
               if self.num_keys >= self.capacity:
                     # delete first node when over capacity
                     lowercase_     			=   self.list.head.next

                     # guaranteed to have a non-None first node when num_keys > 0
                     # explain to type checker via assertions
                     assert first_node is not None
                     assert first_node.key is not None
                     assert self.list.remove(__lowerCAmelCase) is not None
                     # first_node guaranteed to be in list

                     del self.cache[first_node.key]
                     self.num_keys -= 1
               lowercase_     			=   DoubleLinkedListNode(__lowerCAmelCase ,		__lowerCAmelCase)
               self.list.add(self.cache[key])
               self.num_keys += 1

         else:
               lowercase_     			=   self.list.remove(self.cache[key])
               assert node is not None  # node guaranteed to be in list
               lowercase_     			=   value
               self.list.add(__lowerCAmelCase)


   @classmethod
   def __UpperCAmelCase							( cls					:						type[LFUCache[T, U]] ,		__lowerCAmelCase					:						int = 128)   ->       Callable[[Callable[[T], U]], Callable[..., U]]:

         def cache_decorator_inner(__lowerCAmelCase					:						Callable[[T], U]) -> Callable[..., U]:
               def cache_decorator_wrapper(*__lowerCAmelCase					:						T) -> U:
                     if func not in cls.decorator_function_to_instance_map:
                           lowercase_     			=   LFUCache(__lowerCAmelCase)

                     lowercase_     			=   cls.decorator_function_to_instance_map[func].get(args[0])
                     if result is None:
                           lowercase_     			=   func(*__lowerCAmelCase)
                           cls.decorator_function_to_instance_map[func].put(args[0] ,		__lowerCAmelCase)
                     return result

               def cache_info() -> LFUCache[T, U]:
                     return cls.decorator_function_to_instance_map[func]

               setattr(__lowerCAmelCase ,		"cache_info" ,		__lowerCAmelCase)  # noqa: B010

               return cache_decorator_wrapper

         return cache_decorator_inner


if __name__ == "__main__":
       import doctest

       doctest.testmod()







'''simple docstring'''

from hashlib import mda, shaaaa

lowerCAmelCase_			:			Union[str, Any]    	=   (shaaaa, mda)





class 				lowercase    :


   def __init__( self					:						Optional[Any] ,		__lowerCAmelCase					:						int = 8)   ->       None:
         lowercase_     			=   0B0
         lowercase_     			=   size


   def __UpperCAmelCase							( self					:						Dict ,		__lowerCAmelCase					:						str)   ->       None:
         lowercase_     			=   self.hash_(__lowerCAmelCase)
         self.bitarray |= h


   def __UpperCAmelCase							( self					:						Union[str, Any] ,		__lowerCAmelCase					:						str)   ->       bool:
         lowercase_     			=   self.hash_(__lowerCAmelCase)
         return (h & self.bitarray) == h


   def __contains__( self					:						str ,		__lowerCAmelCase					:						str)   ->       bool:
         return self.exists(__lowerCAmelCase)


   def __UpperCAmelCase							( self					:						Union[str, Any] ,		__lowerCAmelCase					:						int)   ->       str:
         lowercase_     			=   bin(__lowerCAmelCase)[2:]
         return res.zfill(self.size)


   @property
   def __UpperCAmelCase							( self					:						Dict)   ->       str:
         return self.format_bin(self.bitarray)


   def __UpperCAmelCase							( self					:						Any ,		__lowerCAmelCase					:						str)   ->       int:
         lowercase_     			=   0B0
         for func in HASH_FUNCTIONS:
               lowercase_     			=   (
                   int.from_bytes(func(value.encode()).digest() ,		"little") % self.size
               )
               res |= 2**position
         return res


   def __UpperCAmelCase							( self					:						Union[str, Any] ,		__lowerCAmelCase					:						str)   ->       str:
         return self.format_bin(self.hash_(__lowerCAmelCase))


   @property
   def __UpperCAmelCase							( self					:						str)   ->       float:
         lowercase_     			=   bin(self.bitarray).count("1")
         return (n_ones / self.size) ** len(__lowerCAmelCase)






