"""High performance data structures"""## Copied and completed from the sandbox of CPython# (nondist/sandbox/collections/pydeque.py rev 1.1, Raymond Hettinger)#importoperatortry:fromthreadimportget_identas_thread_identexceptImportError:def_thread_ident():return-1n=30LFTLNK=nRGTLNK=n+1BLOCKSIZ=n+2# The deque's size limit is d.maxlen. The limit can be zero or positive, or# None. After an item is added to a deque, we check to see if the size has# grown past the limit. If it has, we get the size back down to the limit by# popping an item off of the opposite end. The methods that can trigger this# are append(), appendleft(), extend(), and extendleft().classdeque(object):def__new__(cls,iterable=(),*args,**kw):self=super(deque,cls).__new__(cls,*args,**kw)self.clear()returnselfdef__init__(self,iterable=(),maxlen=None):self.clear()ifmaxlenisnotNone:ifmaxlen<0:raiseValueError("maxlen must be non-negative")self._maxlen=maxlenadd=self.appendforeleminiterable:add(elem)@propertydefmaxlen(self):returnself._maxlendefclear(self):self.right=self.left=[None]*BLOCKSIZself.rightndx=n//2# points to last written elementself.leftndx=n//2+1self.length=0self.state=0defappend(self,x):self.state+=1self.rightndx+=1ifself.rightndx==n:newblock=[None]*BLOCKSIZself.right[RGTLNK]=newblocknewblock[LFTLNK]=self.rightself.right=newblockself.rightndx=0self.length+=1self.right[self.rightndx]=xifself.maxlenisnotNoneandself.length>self.maxlen:self.popleft()defappendleft(self,x):self.state+=1self.leftndx-=1ifself.leftndx==-1:newblock=[None]*BLOCKSIZself.left[LFTLNK]=newblocknewblock[RGTLNK]=self.leftself.left=newblockself.leftndx=n-1self.length+=1self.left[self.leftndx]=xifself.maxlenisnotNoneandself.length>self.maxlen:self.pop()defextend(self,iterable):ifiterableisself:iterable=list(iterable)foreleminiterable:self.append(elem)defextendleft(self,iterable):ifiterableisself:iterable=list(iterable)foreleminiterable:self.appendleft(elem)defpop(self):ifself.leftisself.rightandself.leftndx>self.rightndx:raiseIndexError,"pop from an empty deque"x=self.right[self.rightndx]self.right[self.rightndx]=Noneself.length-=1self.rightndx-=1self.state+=1ifself.rightndx==-1:prevblock=self.right[LFTLNK]ifprevblockisNone:# the deque has become empty; recenter instead of freeing blockself.rightndx=n//2self.leftndx=n//2+1else:prevblock[RGTLNK]=Noneself.right[LFTLNK]=Noneself.right=prevblockself.rightndx=n-1returnxdefpopleft(self):ifself.leftisself.rightandself.leftndx>self.rightndx:raiseIndexError,"pop from an empty deque"x=self.left[self.leftndx]self.left[self.leftndx]=Noneself.length-=1self.leftndx+=1self.state+=1ifself.leftndx==n:prevblock=self.left[RGTLNK]ifprevblockisNone:# the deque has become empty; recenter instead of freeing blockself.rightndx=n//2self.leftndx=n//2+1else:prevblock[LFTLNK]=Noneself.left[RGTLNK]=Noneself.left=prevblockself.leftndx=0returnxdefcount(self,value):c=0foriteminself:ifitem==value:c+=1returncdefremove(self,value):# Need to be defensive for mutating comparisonsforiinrange(len(self)):ifself[i]==value:delself[i]returnraiseValueError("deque.remove(x): x not in deque")defrotate(self,n=1):length=len(self)iflength==0:returnhalflen=(length+1)>>1ifn>halflenorn<-halflen:n%=lengthifn>halflen:n-=lengthelifn<-halflen:n+=lengthwhilen>0:self.appendleft(self.pop())n-=1whilen<0:self.append(self.popleft())n+=1defreverse(self):"reverse *IN PLACE*"leftblock=self.leftrightblock=self.rightleftindex=self.leftndxrightindex=self.rightndxforiinrange(self.length//2):# Validate that pointers haven't met in the middleassertleftblock!=rightblockorleftindex<rightindex# Swap(rightblock[rightindex],leftblock[leftindex])=(leftblock[leftindex],rightblock[rightindex])# Advance left block/index pairleftindex+=1ifleftindex==n:leftblock=leftblock[RGTLNK]assertleftblockisnotNoneleftindex=0# Step backwards with the right block/index pairrightindex-=1ifrightindex==-1:rightblock=rightblock[LFTLNK]assertrightblockisnotNonerightindex=n-1def__repr__(self):threadlocalattr='__repr'+str(_thread_ident())ifthreadlocalattrinself.__dict__:return'deque([...])'else:self.__dict__[threadlocalattr]=Truetry:ifself.maxlenisnotNone:return'deque(%r, maxlen=%s)'%(list(self),self.maxlen)else:return'deque(%r)'%(list(self),)finally:delself.__dict__[threadlocalattr]def__iter__(self):returndeque_iterator(self,self._iter_impl)def_iter_impl(self,original_state,giveup):ifself.state!=original_state:giveup()block=self.leftwhileblock:l,r=0,nifblockisself.left:l=self.leftndxifblockisself.right:r=self.rightndx+1foreleminblock[l:r]:yieldelemifself.state!=original_state:giveup()block=block[RGTLNK]def__reversed__(self):returndeque_iterator(self,self._reversed_impl)def_reversed_impl(self,original_state,giveup):ifself.state!=original_state:giveup()block=self.rightwhileblock:l,r=0,nifblockisself.left:l=self.leftndxifblockisself.right:r=self.rightndx+1foreleminreversed(block[l:r]):yieldelemifself.state!=original_state:giveup()block=block[LFTLNK]def__len__(self):#sum = 0#block = self.left#while block:# sum += n# block = block[RGTLNK]#return sum + self.rightndx - self.leftndx + 1 - nreturnself.lengthdef__getref(self,index):ifindex>=0:block=self.leftwhileblock:l,r=0,nifblockisself.left:l=self.leftndxifblockisself.right:r=self.rightndx+1span=r-lifindex<span:returnblock,l+indexindex-=spanblock=block[RGTLNK]else:block=self.rightwhileblock:l,r=0,nifblockisself.left:l=self.leftndxifblockisself.right:r=self.rightndx+1negative_span=l-rifindex>=negative_span:returnblock,r+indexindex-=negative_spanblock=block[LFTLNK]raiseIndexError("deque index out of range")def__getitem__(self,index):block,index=self.__getref(index)returnblock[index]def__setitem__(self,index,value):block,index=self.__getref(index)block[index]=valuedef__delitem__(self,index):length=len(self)ifindex>=0:ifindex>=length:raiseIndexError("deque index out of range")self.rotate(-index)self.popleft()self.rotate(index)else:index=~indexifindex>=length:raiseIndexError("deque index out of range")self.rotate(index)self.pop()self.rotate(-index)def__reduce_ex__(self,proto):returntype(self),(list(self),self.maxlen)def__hash__(self):raiseTypeError,"deque objects are unhashable"def__copy__(self):returnself.__class__(self,self.maxlen)# XXX make comparison more efficientdef__eq__(self,other):ifisinstance(other,deque):returnlist(self)==list(other)else:returnNotImplementeddef__ne__(self,other):ifisinstance(other,deque):returnlist(self)!=list(other)else:returnNotImplementeddef__lt__(self,other):ifisinstance(other,deque):returnlist(self)<list(other)else:returnNotImplementeddef__le__(self,other):ifisinstance(other,deque):returnlist(self)<=list(other)else:returnNotImplementeddef__gt__(self,other):ifisinstance(other,deque):returnlist(self)>list(other)else:returnNotImplementeddef__ge__(self,other):ifisinstance(other,deque):returnlist(self)>=list(other)else:returnNotImplementeddef__iadd__(self,other):self.extend(other)returnselfclassdeque_iterator(object):def__init__(self,deq,itergen):self.counter=len(deq)defgiveup():self.counter=0raiseRuntimeError,"deque mutated during iteration"self._gen=itergen(deq.state,giveup)defnext(self):res=self._gen.next()self.counter-=1returnresdef__iter__(self):returnselfclassdefaultdict(dict):def__init__(self,*args,**kwds):iflen(args)>0:default_factory=args[0]args=args[1:]ifnotcallable(default_factory)anddefault_factoryisnotNone:raiseTypeError("first argument must be callable")else:default_factory=Noneself.default_factory=default_factorysuper(defaultdict,self).__init__(*args,**kwds)def__missing__(self,key):# from defaultdict docsifself.default_factoryisNone:raiseKeyError(key)self[key]=value=self.default_factory()returnvaluedef__repr__(self,recurse=set()):ifid(self)inrecurse:return"defaultdict(...)"try:recurse.add(id(self))return"defaultdict(%s, %s)"%(repr(self.default_factory),super(defaultdict,self).__repr__())finally:recurse.remove(id(self))defcopy(self):returntype(self)(self.default_factory,self)def__copy__(self):returnself.copy()def__reduce__(self):""" __reduce__ must return a 5-tuple as follows: - factory function - tuple of args for the factory function - additional state (here None) - sequence iterator (here None) - dictionary iterator (yielding successive (key, value) pairs This API is used by pickle.py and copy.py. """return(type(self),(self.default_factory,),None,None,self.iteritems())