# Path: cloudvolume/lru.py
# class LRU:
#   """
#   A Least Recently Used dict implementation based on
#   a dict + a doubly linked list.
#   """
#   def __init__(self, size:int = 100, size_in_bytes:bool = False):
#     """
#     size specifies the upper inclusive limit to the size of the
#     LRU.
# 
#     If size_in_bytes is False, this refers to the number of elements
#     in the LRU.
#     If size_in_bytes is True, this refers to the size in bytes of the
#     stored elements (not counting internal data structures of the LRU)
#     as measured by sys.getsizeof which does not handle nested objects
#     (unless they implement a __sizeof__ handler).
# 
#     Therefore, size_in_bytes is most easily used with Python base types.
#     It was designed for with byte strings in mind that represent file
#     content.
#     """
#     self.size = int(size)
#     self.size_in_bytes = size_in_bytes
#     self.nbytes = 0
#     self.queue = DoublyLinkedList()
#     self.hash = {}
#     self.lock = threading.Lock()
# 
#   def __len__(self):
#     return self.queue.size
# 
#   def keys(self):
#     return self.hash.keys()
# 
#   def values(self):
#     return ( node.val for val in self.queue )
# 
#   def items(self):
#     return ( (key, node.val) for key, node in self.hash.items() )
# 
#   def is_oversized(self):
#     if self.size_in_bytes:
#       return self.nbytes > self.size
#     return len(self.queue) > self.size
# 
#   def clear(self):
#     with self.lock:
#       self.queue = DoublyLinkedList()
#       self.hash = {}
#       self.nbytes = 0
# 
#   def resize(self, new_size):
#     if new_size < 0:
#       raise ValueError("The LRU limit must be a positive number. Got: " + str(new_size))
# 
#     if new_size == 0:
#       self.clear()
#       return
# 
#     with self.lock:
#       try:
#         if new_size >= self.size:
#           return
#       finally:
#         self.size = int(new_size)
# 
#       while self.is_oversized():
#         (key,val) = self.queue.delete_tail()
#         del self.hash[key]
#         self.nbytes -= sys.getsizeof(val)
# 
#   def delete(self, key):
#     with self.lock:
#       if key not in self.hash:
#         raise KeyError("{} not in cache.".format(key))
# 
#       node = self.hash[key]
#       self.queue.delete(node)
#       del self.hash[key]
#       self.nbytes -= sys.getsizeof(node.val)
#       return node.val
# 
#   def pop(self, key, *args):
#     try:
#       return self.delete(key)
#     except KeyError:
#       if len(args):
#         return args[0]
#       raise
#   
#   def get(self, key, default=None):
#     with self.lock:
#       if key not in self.hash:
#         if default is None:
#           raise KeyError("{} not in cache.".format(key))
#         return default
# 
#       node = self.hash[key]
#       self.queue.promote_to_head(node)
# 
#       return node.val[1]
# 
#   def set(self, key, val):
#     with self.lock:
#       if self.size == 0:
#         return
# 
#       pair = (key,val)
#       if key in self.hash:
#         node = self.hash[key]
#         node.val = pair
#         self.queue.promote_to_head(node)
#         return
# 
#       self.queue.prepend(pair)
#       self.hash[key] = self.queue.head
#       self.nbytes += sys.getsizeof(val)
# 
#       while self.is_oversized():
#         (tkey,tval) = self.queue.delete_tail()
#         del self.hash[tkey]
#         self.nbytes -= sys.getsizeof(tval)
# 
#   def __contains__(self, key):
#     return key in self.hash
# 
#   def __getitem__(self, key):
#     return self.get(key)
# 
#   def __setitem__(self, key, val):
#     return self.set(key, val)
# 
#   def __delitem__(self, key):
#     return self.delete(key)
# 
#   def __str__(self):
#     return str(self.queue)
# 
#   def __getstate__(self):
#     # Copy the object's state from self.__dict__ which contains
#     # all our instance attributes. Always use the dict.copy()
#     # method to avoid modifying the original state.
#     state = self.__dict__.copy()
#     # Remove the unpicklable entries.
#     del state['lock']
#     return state
# 
#   def __setstate__(self, state):
#     # Restore instance attributes (i.e., filename and lineno).
#     self.__dict__.update(state)
#     self.lock = threading.Lock()


import pytest
import time
import random
import sys
from cloudvolume.lru import LRU



@pytest.mark.parametrize("size_in_bytes", (False,True))
def test_lru(size_in_bytes):
  base_size = 5
  size = base_size
  small_int_bytes = sys.getsizeof(100)
  if size_in_bytes:
    size *= small_int_bytes


# Path: cloudvolume/lru.py
# class LRU:
#   """
#   A Least Recently Used dict implementation based on
#   a dict + a doubly linked list.
#   """
#   def __init__(self, size:int = 100, size_in_bytes:bool = False):
#     """
#     size specifies the upper inclusive limit to the size of the
#     LRU.
# 
#     If size_in_bytes is False, this refers to the number of elements
#     in the LRU.
#     If size_in_bytes is True, this refers to the size in bytes of the
#     stored elements (not counting internal data structures of the LRU)
#     as measured by sys.getsizeof which does not handle nested objects
#     (unless they implement a __sizeof__ handler).
# 
#     Therefore, size_in_bytes is most easily used with Python base types.
#     It was designed for with byte strings in mind that represent file
#     content.
#     """
#     self.size = int(size)
#     self.size_in_bytes = size_in_bytes
#     self.nbytes = 0
#     self.queue = DoublyLinkedList()
#     self.hash = {}
#     self.lock = threading.Lock()
# 
#   def __len__(self):
#     return self.queue.size
# 
#   def keys(self):
#     return self.hash.keys()
# 
#   def values(self):
#     return ( node.val for val in self.queue )
# 
#   def items(self):
#     return ( (key, node.val) for key, node in self.hash.items() )
# 
#   def is_oversized(self):
#     if self.size_in_bytes:
#       return self.nbytes > self.size
#     return len(self.queue) > self.size
# 
#   def clear(self):
#     with self.lock:
#       self.queue = DoublyLinkedList()
#       self.hash = {}
#       self.nbytes = 0
# 
#   def resize(self, new_size):
#     if new_size < 0:
#       raise ValueError("The LRU limit must be a positive number. Got: " + str(new_size))
# 
#     if new_size == 0:
#       self.clear()
#       return
# 
#     with self.lock:
#       try:
#         if new_size >= self.size:
#           return
#       finally:
#         self.size = int(new_size)
# 
#       while self.is_oversized():
#         (key,val) = self.queue.delete_tail()
#         del self.hash[key]
#         self.nbytes -= sys.getsizeof(val)
# 
#   def delete(self, key):
#     with self.lock:
#       if key not in self.hash:
#         raise KeyError("{} not in cache.".format(key))
# 
#       node = self.hash[key]
#       self.queue.delete(node)
#       del self.hash[key]
#       self.nbytes -= sys.getsizeof(node.val)
#       return node.val
# 
#   def pop(self, key, *args):
#     try:
#       return self.delete(key)
#     except KeyError:
#       if len(args):
#         return args[0]
#       raise
#   
#   def get(self, key, default=None):
#     with self.lock:
#       if key not in self.hash:
#         if default is None:
#           raise KeyError("{} not in cache.".format(key))
#         return default
# 
#       node = self.hash[key]
#       self.queue.promote_to_head(node)
# 
#       return node.val[1]
# 
#   def set(self, key, val):
#     with self.lock:
#       if self.size == 0:
#         return
# 
#       pair = (key,val)
#       if key in self.hash:
#         node = self.hash[key]
#         node.val = pair
#         self.queue.promote_to_head(node)
#         return
# 
#       self.queue.prepend(pair)
#       self.hash[key] = self.queue.head
#       self.nbytes += sys.getsizeof(val)
# 
#       while self.is_oversized():
#         (tkey,tval) = self.queue.delete_tail()
#         del self.hash[tkey]
#         self.nbytes -= sys.getsizeof(tval)
# 
#   def __contains__(self, key):
#     return key in self.hash
# 
#   def __getitem__(self, key):
#     return self.get(key)
# 
#   def __setitem__(self, key, val):
#     return self.set(key, val)
# 
#   def __delitem__(self, key):
#     return self.delete(key)
# 
#   def __str__(self):
#     return str(self.queue)
# 
#   def __getstate__(self):
#     # Copy the object's state from self.__dict__ which contains
#     # all our instance attributes. Always use the dict.copy()
#     # method to avoid modifying the original state.
#     state = self.__dict__.copy()
#     # Remove the unpicklable entries.
#     del state['lock']
#     return state
# 
#   def __setstate__(self, state):
#     # Restore instance attributes (i.e., filename and lineno).
#     self.__dict__.update(state)
#     self.lock = threading.Lock()


# Path: test/test_lru.py
import pytest
import time
import random
import sys
from cloudvolume.lru import LRU




@pytest.mark.parametrize("size_in_bytes", (False,True))
def test_lru(size_in_bytes):
  base_size = 5
  size = base_size
  small_int_bytes = sys.getsizeof(100)
  if size_in_bytes:
    size *= small_int_bytes


  lru = LRU(size, size_in_bytes=size_in_bytes)