def __del_entry(self, s, quot): ''' Remove the entry in QF[s] and slide the rest of the cluster forward. ''' orig = s curr = self[s] sp = self.inc_index(s) while True: _next = self[sp] curr_occupied = is_occupied(curr) if is_empty(_next) or isElementClusterStart(_next) or sp == orig: self[s] = 0 return # Fix entries which slide into canonical slots. updated_next = _next if isElementRunStart(_next): do = True while do: quot = self.inc_index(quot) do = not is_occupied(self[quot]) if curr_occupied and quot == s: updated_next = is_shifted_clear(_next) self[s] = is_occupied_set(updated_next) if curr_occupied else is_occupied_clear(updated_next) s = sp sp = self.inc_index(sp) curr = _next
def insert(self, val, hashed=False): if self.entries >= self.MAX_INSERTIONS or self.overflowed: # Can't safely process an after overflow # Only a buggy program would attempt it if self.overflowed: raise OverflowError #Can still resize if we have enough remainder bits if self.REMAINDER_BITS > 1: self.double_size() else: self.overflowed = True raise OverflowError if hashed: _hash = val else: _hash = self.hash_fn(val) fq = self.hash_to_quotient(_hash) fr = self.hash_to_remainder(_hash) T_fq = self[fq] entry = (fr << 3) & ~7 #Special-case filling canonical slots to simplify insert_into() if is_empty(T_fq): entry = is_occupied_set(entry) self[fq] = entry self.entries += 1 return if not is_occupied(T_fq): self[fq] = is_occupied_set(T_fq) start = self.find_run_Index(fq) s = start if is_occupied(T_fq): do = True while do: rem = get_remainder(self[s]) if rem >= fr: break s = self.inc_index(s) do = is_continuation(self[s]) if s == start: # The old start-of-run becomes a continuation. old_head = self[start] old_head = is_continuation_set(old_head) self[start] = old_head else: # The new element becomes a continuation. entry = is_continuation_set(entry) #Set the shifted bit if we can't use the canonical slot. if s != fq: entry = is_shifted_set(entry) self.insert_into(s, entry) self.entries += 1
def __delitem__(self, val): if self.overflowed: #Can't safely process a remove after overflow #Only a buggy program would attempt it raise OverflowError _hash = self.hash_fn(val) fq = self.hash_to_quotient(_hash) fr = self.hash_to_remainder(_hash) T_fq = self[fq] if self.entries == 0 or not is_occupied(T_fq ): #If you remove things that don't exist it's possible you will clobber #somethign on a collision, your program is buggy raise KeyError('Element not exist') start = self.find_run_Index(fq) s = start #Find the offending table index (or give up) do = True while do: rem = get_remainder(self[s]) if rem == fr: break elif rem > fr: return s = self.inc_index(s) do = is_continuation(self[s]) if rem != fr: #If you remove things that don't exist it's possible you will clobber #somethign on a collision, your program is buggy raise KeyError('Element not exist') kill = T_fq if s == fq else self[s] replace_run_start = isElementRunStart(kill) #If we're deleting the last entry in a run, clear `is_occupied'. if replace_run_start: _next = self[self.inc_index(s)] if not is_continuation(_next): T_fq = is_occupied_clear(T_fq) self[fq] = T_fq self.__del_entry(s, fq) if replace_run_start: _next = self[s] updated_next = _next if is_continuation(_next):# The new start-of-run is no longer a continuation. updated_next = is_continuation_clear(updated_next) if s == fq and isElementRunStart(updated_next): # The new start-of-run is in the canonical slot. updated_next = is_shifted_clear(updated_next) if updated_next != _next: self[s] = updated_next self.entries -= 1
def insert_into(self, s, elt): curr = elt do = True while do: prev = self[s] empty = is_empty(prev) if not empty:# Fix up `is_shifted' and `is_occupied'. prev = is_shifted_set(prev) if is_occupied(prev): curr = is_occupied_set(curr) prev = is_occupied_clear(prev) self[s]=curr curr = prev s = self.inc_index(s) do = not empty
def find_run_Index(self, fq): ''' Find the start index of the run for fq (given that the run exists) ''' # Find the start of the cluster. b= fq while is_shifted(self[b]): b= self.dec_index(b) # Find the start of the run for fq s = b while b != fq: s = self.inc_index(s) while is_continuation(self[s]): s = self.inc_index(s) b = self.inc_index(b) while not is_occupied(self[b]): b = self.inc_index(b) return s
def __next__(self): while self.entries != self.visited: elt = self[self.index] #Keep track of the current run. if isElementClusterStart(elt): self.quotient = self.index elif isElementRunStart(elt): quot = self.quotient do = True while do: quot = self.inc_index(quot) do = not is_occupied(self[quot]) self.quotient = quot self.index = self.inc_index(self.index) if not is_empty(elt): quot = self.quotient rem = get_remainder(elt) _hash = (quot << self.REMAINDER_BITS) | rem self.visited += 1 return _hash raise StopIteration()