require"./sqrt_set.cr"moduleNgLibclassSqrtMap(K,V)includeEnumerable({K,V})includeIterable({K,V})@keys:NgLib::SqrtSet(K)@values:Hash(K,V)@block:(self,K->V)?delegatesize,to:@keysdefself.new(default_value:V)new{default_value}enddefself.new(&block:self,K->V)newblockenddefinitialize(@block:(self,K->V)?=nil)@keys=NgLib::SqrtSet(K).new@values=Hash(K,V).newenddefself.new(hash:Hash(K,V))map=self.newhash.eachdo|key,value|map[key]=valueendmapenddefself.zip(keys:Array(K),values:Array(V))map=self.newkeys.zip(values)do|key,value|map[key]=valueendmapenddefput(key:K,value:V,&)item=upsert(key,value)item?item[1]:yieldkeyenddef[](key:K):Vfetch(key){ifblock=@blockblock.call(self,key)elseraiseKeyError.new"Missing hash key: #{key.inspect}"end}enddef[]?(key:K):V?fetch(key,nil)enddef[]=(key:K,value:V):Vupsert(key,value)valueenddeffetch(key:K,&)has_key?(key)?@values[key]:yieldkeyenddeffetch(key:K,default_value)fetch(key){default_value}enddefhas_key?(key:K):Bool@values.has_key?(key)enddefupdate(key:K,&:V->V):Vifhas_key?(key)self[key]=yieldself[key]elsifblock=@blockdefault_value=block.call(self,key)upsert(key,yielddefault_value)default_valueelseraiseKeyError.new"Missing hash key: #{key.inspect}"endenddefdelete(key:K):V?returnnilunlesshas_key?(key)@keys.delete(key)@values.delete(key)enddefunsafe_fetch(index:Int):{K,V}key=@keys.unsafe_fetch(index){key,@values[key]}enddeffetch_at(index:Int,&)index+=sizeifindex<0returnyieldindexunless0<=index&&index<sizeunsafe_fetch(index)enddeffetch_at(index:Int,default_value)fetch_at(index){default_value}enddefat(index:Int):{K,V}fetch_at(index){raiseIndexError.new}end# Returns the key-value at the *index*-th.
defat(index:Int,&)fetch_at(index){|i|yieldi}end# Like `at`, but returns `nil`
# if trying to access an key-value outside the set's range.
defat?(index:Int):{K,V}?fetch_at(index){nil}end# Returns the key at the *index*-th.
defkey_at(index:Int):Kret=fetch_at(index,nil)ifret.nil?raiseIndexError.newelseret[0]endend# Like `at`, but returns `nil`
# if trying to access an key outside the set's range.
defkey_at?(index:Int):K?item=at?(index)item.try&.[0]end# Returns the value at the *index*-th.
defvalue_at(index:Int):Vret=fetch_at(index,nil)ifret.nil?raiseIndexError.newelseret[1]endend# Like `at`, but returns `nil`
# if trying to access an value outside the set's range.
defvalue_at?(index:Int):V?item=at?(index)item.try&.[1]enddefkeys:Array(K)map&.[0]enddefvalues:Array(V)map&.[1]enddefvalues_by_key(*keys:K)keys.map{|key|self[key]}enddefvalues_at(*indices:Int)indices.map{|index|value_at(index)}enddefinvert:SqrtMap(V,K)inverted=SqrtMap(V,K).neweachdo|key,value|inverted[value]=keyendinvertedenddefkey_for(value):Kkey_for(value){raiseKeyError.new"Missing hash key for value: #{value}"}enddefkey_for?(value):K?key_for(value){nil}enddefkey_for(value,&)eachdo|k,v|returnkifv==valueendyieldvalueenddefeach(&):Nil@keys.eachdo|key|yield({key,@values[key]})endenddefeach:Iterator({K,V})@keys.each.map{|key|{key,@values[key]}}endprivatedefupsert(key:K,value:V):{K,V}?ifhas_key?(key)old_value=@values[key]@values[key]=value{key,old_value}else@keys.add(key)@values[key]=valuenilendendendend
# require "./sqrt_set.cr"
moduleNgLibclassSqrtSet(T)includeEnumerable(T)includeIndexable(T)includeIndexable::Mutable(T)BUCKET_RATIO=16SPLIT_RATIO=24@values:Array(Array(T))gettersize:Int32definitialize@values=Array(Array(T)).new@size=0enddefinitialize(enumerable:Enumerable(T))a=enumerable.to_an=enumerable.sizeif(0...n-1).any?{|i|a[i]>a[i+1]}a.sort!endif(0...n-1).any?{|i|a[i]>=a[i+1]}a,b=[]ofT,ab.eachdo|x|ifa.empty?||a.last!=xa<<xendendendn=@size=a.sizen_buckets=(Math.sqrt(n/BUCKET_RATIO)).ceil.to_i@values=Array.new(n_buckets){|i|a[n.to_i64*i// n_buckets...n.to_i64 * (i + 1) // n_buckets] }enddefunsafe_fetch(index:Int)@values.eachdo|e|ifindex<e.sizereturne.unsafe_fetch(index)endindex-=e.sizeendraiseIndexError.newenddefunsafe_put(index:Int,value:T)@values.eachdo|e|ifindex<e.sizereturne.unsafe_put(index,value)endindex-=e.sizeendvalueenddefat(index:Int)fetch(index){raiseIndexError.new}enddefat(index:Int,&)fetch(index){|i|yieldi}enddefat?(index:Int)fetch(index){nil}enddefminfirstenddefmin?first?enddefmaxlastenddefmax?last?enddefindex(object)ans=0@values.eachdo|e|ife.last>=objecti=e.bsearch_index{|x|x>=object}||e.sizereturne[i]==object?ans+i:nilendans+=e.sizeendnilenddefindex!(object)index(object)||raiseEnumerable::NotFoundError.newenddefrindex(object)ans=0@values.eachdo|e|ife.last>=objecti=(e.bsearch_index{|x|x>object}||e.size)-1returne[i]==object?ans+i:nilendans+=e.sizeendnilenddefrindex!(object)rindex(object)||raiseEnumerable::NotFoundError.newenddefcount(object)includes?(object)?1:0enddefcount(range:Range(T?,T?))b,e=range.begin,range.endleft=b?lower_bound_index(b):0right=ife.nil?@sizeelseifrange.exclusive?lower_bound_index(e)elseupper_bound_index(e)endendright-leftenddefupper_bound(object:T)@values.eachdo|e|ife.last>objectreturne.bsearch{|x|x>object}endendnilenddeflower_bound(object:T)@values.eachdo|e|ife.last>=objectreturne.bsearch{|x|x>=object}endendnilenddeflargest_less_than(object)@values.reverse_eachdo|e|ife.first<objecti=e.bsearch_index{|x|x>=object}||e.sizereturne[i-1]endendnilenddeflargest_less_than_or_equal_to(object)@values.reverse_eachdo|e|ife.first<=objecti=e.bsearch_index{|x|x>object}||e.sizereturne[i-1]endendnilenddefsmallest_greater_than(object)upper_bound(object)enddefsmallest_greater_than_or_equal_to(object)lower_bound(object)enddef>(other)smallest_greater_than(other)enddef>=(other)smallest_greater_than_or_equal_to(other)enddef<(other)largest_less_than(other)enddef<=(other)largest_less_than_or_equal_to(other)enddefeach(&:T->):Nil@values.eachdo|e|e.eachdo|x|yieldxendendenddefincludes?(elem:T)returnfalseif@size==0a,_,i=find(elem)i!=a.size&&a[i]==elemenddefadd(elem:T):selfself<<elemenddefadd?(elem:T):Boolifsize==0@values=[[elem]]@size=1returntrueenda,b,i=find(elem)returnfalseifi!=a.size&&a[i]==elema.insert(i,elem)@size+=1ifa.size>@values.size*SPLIT_RATIOmid=a.size>>1@values[b...b+1]=[a[...mid],a[mid...]]endtrueenddefconcat(elems)elems.each{|elem|self<<elem}selfenddef<<(elem:T):selfifsize==0@values=[[elem]]@size=1returnselfenda,b,i=find(elem)returnselfifi!=a.size&&a[i]==elema.insert(i,elem)@size+=1ifa.size>@values.size*SPLIT_RATIOmid=a.size>>1@values[b...b+1]=[a[...mid],a[mid...]]endselfenddefdelete(object):selfreturnselfif@size==0a,b,i=find(object)returnselfifi==a.size||a[i]!=objectpop_impl(a,b,i)selfenddefdelete_at(index:Int,&)index+=@sizeifindex<0returnyieldindexifindex<0@values.each_with_indexdo|e,i|ifindex<e.sizereturnpop_impl(e,i,index)endindex-=e.sizeendyieldindexenddefshift:Tshift{raiseIndexError.new}enddefshift(&)delete_at(0){yield}enddefshift?:T?shift{nil}enddefpop(&)delete_at(@size-1){yield}enddefpoppop{raiseIndexError.new}enddefpop?pop{nil}enddefclear@values.clear@size=0enddefempty?@size==0enddef&(other:self):selfsmaller,larger=size<=other.size?{self,other}:{other,self}set=SqrtSet(T).newsmaller.eachdo|object|set<<objectiflarger.includes?(object)endsetenddef|(other:SqrtSet(U)):SqrtSet(T|U)forallUset=SqrtSet(T|U).neweach{|object|set<<object}other.each{|object|set<<object}setenddef+(other:SqrtSet(U)):SqrtSet(T|U)forallUself|otherenddef-(other:SqrtSet)set=SqrtSet(T).neweachdo|value|set<<valueunlessother.includes?(value)endsetenddef-(other:Enumerable)clone.subtractotherenddef^(other:Enumerable(U))forallUset=SqrtSet(T|U).new(self)other.eachdo|value|ifincludes?(value)set.deletevalueelseset<<valueendendsetenddefsubtract(other:Enumerable)other.eachdo|value|deletevalueendselfenddef===(other:T)includes?otherenddefintersects?(other)ifsize<other.sizeany?{|object|other.includes?(object)}elseother.any?{|object|includes?(object)}endenddefsubset_of?(other)returnfalseifother.size<sizeall?{|value|other.includes?(value)}enddefproper_subset_of?(other)returnfalseifother.size<=sizeall?{|value|other.includes?(value)}enddefsuperset_of?(other)other.subset_of?(self)enddefproper_superset_of?(other)other.proper_subset_of?(self)enddefdupset=SqrtSet(T).neweach{|object|set<<object}setenddefcloneset=SqrtSet(T).neweach{|object|set<<object}setenddefto_a@values.flattenenddefinspect(io:IO)to_s(io)enddefto_s(io:IO)io<<"SqrtSet{"joinio,", ",&.inspect(io)io<<'}'endprivatedeflower_bound_index(object:T):Int32ans=0@values.eachdo|e|ife.last>=objectreturnans+(e.bsearch_index{|x|x>=object}||e.size)endans+=e.sizeendansendprivatedefupper_bound_index(object:T):Int32ans=0@values.eachdo|e|ife.last>objectreturnans+(e.bsearch_index{|x|x>object}||e.size)endans+=e.sizeendansendprivatedeffind(elem:T)@values.each_with_indexdo|e,i|ifelem<=e.lastreturn{e,i,e.bsearch_index{|x|x>=elem}||e.size}endende=@values[-1]i=@values.size-1return{e,i,e.bsearch_index{|x|x>=elem}||e.size}endprivatedefpop_impl(a,b,i)ans=a.delete_at(i)@size-=1ifa.empty?@values.delete_at(b)endansendendendmoduleNgLibclassSqrtMap(K,V)includeEnumerable({K,V})includeIterable({K,V})@keys:NgLib::SqrtSet(K)@values:Hash(K,V)@block:(self,K->V)?delegatesize,to:@keysdefself.new(default_value:V)new{default_value}enddefself.new(&block:self,K->V)newblockenddefinitialize(@block:(self,K->V)?=nil)@keys=NgLib::SqrtSet(K).new@values=Hash(K,V).newenddefself.new(hash:Hash(K,V))map=self.newhash.eachdo|key,value|map[key]=valueendmapenddefself.zip(keys:Array(K),values:Array(V))map=self.newkeys.zip(values)do|key,value|map[key]=valueendmapenddefput(key:K,value:V,&)item=upsert(key,value)item?item[1]:yieldkeyenddef[](key:K):Vfetch(key){ifblock=@blockblock.call(self,key)elseraiseKeyError.new"Missing hash key: #{key.inspect}"end}enddef[]?(key:K):V?fetch(key,nil)enddef[]=(key:K,value:V):Vupsert(key,value)valueenddeffetch(key:K,&)has_key?(key)?@values[key]:yieldkeyenddeffetch(key:K,default_value)fetch(key){default_value}enddefhas_key?(key:K):Bool@values.has_key?(key)enddefupdate(key:K,&:V->V):Vifhas_key?(key)self[key]=yieldself[key]elsifblock=@blockdefault_value=block.call(self,key)upsert(key,yielddefault_value)default_valueelseraiseKeyError.new"Missing hash key: #{key.inspect}"endenddefdelete(key:K):V?returnnilunlesshas_key?(key)@keys.delete(key)@values.delete(key)enddefunsafe_fetch(index:Int):{K,V}key=@keys.unsafe_fetch(index){key,@values[key]}enddeffetch_at(index:Int,&)index+=sizeifindex<0returnyieldindexunless0<=index&&index<sizeunsafe_fetch(index)enddeffetch_at(index:Int,default_value)fetch_at(index){default_value}enddefat(index:Int):{K,V}fetch_at(index){raiseIndexError.new}end# Returns the key-value at the *index*-th.
defat(index:Int,&)fetch_at(index){|i|yieldi}end# Like `at`, but returns `nil`
# if trying to access an key-value outside the set's range.
defat?(index:Int):{K,V}?fetch_at(index){nil}end# Returns the key at the *index*-th.
defkey_at(index:Int):Kret=fetch_at(index,nil)ifret.nil?raiseIndexError.newelseret[0]endend# Like `at`, but returns `nil`
# if trying to access an key outside the set's range.
defkey_at?(index:Int):K?item=at?(index)item.try&.[0]end# Returns the value at the *index*-th.
defvalue_at(index:Int):Vret=fetch_at(index,nil)ifret.nil?raiseIndexError.newelseret[1]endend# Like `at`, but returns `nil`
# if trying to access an value outside the set's range.
defvalue_at?(index:Int):V?item=at?(index)item.try&.[1]enddefkeys:Array(K)map&.[0]enddefvalues:Array(V)map&.[1]enddefvalues_by_key(*keys:K)keys.map{|key|self[key]}enddefvalues_at(*indices:Int)indices.map{|index|value_at(index)}enddefinvert:SqrtMap(V,K)inverted=SqrtMap(V,K).neweachdo|key,value|inverted[value]=keyendinvertedenddefkey_for(value):Kkey_for(value){raiseKeyError.new"Missing hash key for value: #{value}"}enddefkey_for?(value):K?key_for(value){nil}enddefkey_for(value,&)eachdo|k,v|returnkifv==valueendyieldvalueenddefeach(&):Nil@keys.eachdo|key|yield({key,@values[key]})endenddefeach:Iterator({K,V})@keys.each.map{|key|{key,@values[key]}}endprivatedefupsert(key:K,value:V):{K,V}?ifhas_key?(key)old_value=@values[key]@values[key]=value{key,old_value}else@keys.add(key)@values[key]=valuenilendendendend