Advertisement
Guest User

Untitled

a guest
Jan 18th, 2017
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.16 KB | None | 0 0
  1. import collections
  2. import weakref
  3.  
  4. class MutableKeyDict(collections.MutableMapping):
  5. hashdict = {}
  6. allinstances = []
  7.  
  8. def __new__(cls,*args,**kwargs):
  9. ''' Create a new instance of MutableKeyDict '''
  10. newinstance = super(MutableKeyDict,cls).__new__(cls,*args,**kwargs)
  11. cls.allinstances.append(weakref.ref(newinstance))
  12. return newinstance
  13.  
  14. def __init__(self,dictionary = {}):
  15. self.valdict = {}
  16. # Each object corresponds to a hash:
  17. # For example: mutableobject():value becomes
  18. # hashdict = (hash of mutableobject):mutableobject
  19. # valdict = (hash of mutableobject):value
  20. # This leads to inefficient setting and retreiving of values, though
  21. for key,value in dictionary.iteritems():
  22. keyhash = self.__gethash__(key)
  23. self.hashdict[keyhash] = key
  24. self.valdict[keyhash] = value
  25.  
  26. def __updatehashes__(self,hashmap):
  27. print hashmap
  28. # Recreate the value dictionary based off of the new hashmap.
  29. for oldhash,newhash in hashmap.iteritems():
  30. if oldhash in self.valdict:
  31. val = self.valdict[oldhash]
  32. del self.valdict[oldhash]
  33. self.valdict[newhash] = val
  34.  
  35. def __resethashes__(self):
  36. # Redo hashes of anything that changed. Prevents hash collisions
  37. newhashdict = {}
  38. newvaluedict = {}
  39. hashmapdict = {}
  40. for oldhash,objtohash in self.hashdict.iteritems():
  41. newhash = self.__gethash__(objtohash)
  42. hashmapdict[oldhash] = newhash
  43. newhashdict[newhash] = objtohash
  44. self.hashdict = newhashdict
  45. for inst in self.allinstances:
  46. inst().__updatehashes__(hashmapdict)
  47.  
  48. def __getitem__(self,key):
  49. # Optimized to prevent unneeded hash calculations
  50. self.__resethashes__()
  51. if not key in self.hashdict.values():
  52. try:
  53. return self.default
  54. except AttributeError:
  55. raise KeyError(key)
  56. return self.valdict[self.hashdict.keys()[self.hashdict.values().index(key)]]
  57.  
  58. def __setitem__(self,key,value):
  59. # Optimized to prevent unneeded hash calculations
  60. self.__resethashes__()
  61. if key in self.hashdict.values():
  62. self.valdict[self.hashdict.keys()[self.hashdict.values().index(key)]] = value
  63. else:
  64. keyhash = self.__gethash__(key)
  65. self.hashdict[keyhash] = key
  66. self.valdict[keyhash] = value
  67.  
  68. def __delitem__(self,key):
  69. self.__resethashes__()
  70. if not key in self.hashdict.values():
  71. raise KeyError(key)
  72. else:
  73. hashtodelete = self.hashdict.keys()[self.hashdict.values().index(key)]
  74. if not hashtodelete in self.valdict:
  75. raise KeyError(key)
  76. del self.valdict[hashtodelete]
  77.  
  78. def __gethash__(self,item):
  79. if isinstance(item,collections.Hashable) and (not isinstance(item,collections.MutableMapping)):
  80. return hash(item)
  81. elif hasattr(item,'__dict__'):
  82. return self.__gethash__(item.__dict__)
  83. elif type(item) is dict:
  84. x = 0
  85. for key,value in item.iteritems():
  86. k = self.__gethash__(key) + 2
  87. v = self.__gethash__(value) + 2
  88. x += k^((k << 6)+(v >> 2) + v)
  89. return x + self.__gethash__(item.keys())
  90. elif isinstance(item,list):
  91. x = 0
  92. for i in item:
  93. k = self.__gethash__(i) + 5
  94. x += x^ ((x << 6) + (k >> 2) + k)
  95. return x
  96. elif isinstance(item,dict):
  97. x = 0
  98. for i in item:
  99. k = self.__gethash__(i) + 3
  100. x += x^ ((x << 6) + (k >> 2) + k)
  101. return x
  102. elif isinstance(item,set):
  103. x = 0
  104. for i in list(item):
  105. k = self.__gethash__(i) + 7
  106. x += x^ ((x << 6) + (k >> 2) + k)
  107. return x
  108. else:
  109. raise RuntimeError("Unhashable type " + type(item))
  110.  
  111. def keys(self):
  112. return [self.hashdict[x] for x in self.valdict.keys()]
  113.  
  114. def values(self):
  115. return self.valdict.values()
  116.  
  117. def __len__(self):
  118. return len(self.valdict)
  119.  
  120. def items(self):
  121. return list(zip(self.keys(),self.values()))
  122.  
  123. def iteritems(self):
  124. for key,value in self.valdict.iteritems():
  125. yield (self.hashdict[key],value)
  126. raise StopIteration
  127.  
  128. def __iter__(self):
  129. for key,value in self.valdict.iteritems():
  130. yield self.hashdict[key]
  131. raise StopIteration
  132.  
  133. def __contains__(self,item):
  134. return item in self.keys()
  135.  
  136. def get(self,item,default=None):
  137. # Optimized to prevent unneeded hash calculations
  138. self.__resethashes__()
  139. if not key in self.hashdict.values():
  140. return default
  141. return self.valdict[self.hashdict.keys()[self.hashdict.values().index(key)]]
  142.  
  143. def clear(self):
  144. self.valdict = {}
  145.  
  146. def setdefault(self,default):
  147. self.default = default
  148.  
  149. def pop(self,*args):
  150. if len(args) > 0:
  151. key = self.keys()[-1]
  152. ret = self.get(key,args[0])
  153. if args[0] in self.keys():
  154. del self[args[0]]
  155. return ret
  156. key = self.keys()[-1]
  157. ret = self[key]
  158. del self[key]
  159. return ret
  160.  
  161. def popitem(self):
  162. key = self.keys()[-1]
  163. val = self[key]
  164. del self[key]
  165. return key,val
  166.  
  167. def copy(self):
  168. return self.__class__(self)
  169.  
  170. def update(self,other):
  171. for key,val in other.iteritems():
  172. self[key] = val
  173.  
  174. def __repr__(self,forMutable=False):
  175. ret = '{'
  176. if len(self) == 0:
  177. return '{}'
  178. if forMutable:
  179. return '{...}'
  180. needsComma = False
  181. for k,v in self.iteritems():
  182. if needsComma:
  183. ret += ','
  184. needsComma = True
  185. reprk = k.__repr__(True) if isinstance(k,MutableKeyDict) else repr(k)
  186. reprv = v.__repr__(True) if isinstance(v,MutableKeyDict) else repr(v)
  187. ret += reprk + ':' + reprv
  188. ret += '}'
  189. return ret
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement