class Sequence::List
Attributes
list[R]
pos[R]
Public Class Methods
new(seqs)
click to toggle source
# File lib/sequence/list.rb, line 6 def initialize(seqs) seqs.empty? and raise( ArgumentError, 'empty List not allowed' ) @list=seqs @current_idx=0 @pos=0 @start_pos=[0] @list=@list.inject([]){|li,seq| seq=seq.to_sequence case seq when Circular; raise ArgumentError, 'no circular seqs in lists' when List; li+seq.list else li<<seq end } @list.each{|seq| seq.on_change_notify(self) } _rebuild_idxs extend @list.first.like end
Public Instance Methods
+(other)
click to toggle source
Calls superclass method
# File lib/sequence/list.rb, line 157 def + other return super unless ::Sequence===other return List[*@list+[other]] end
_fragment_discard_after(pos)
click to toggle source
# File lib/sequence/list.rb, line 162 def _fragment_discard_after(pos) idx=_lookup_idx(pos) pos-=@start_pos[idx] @list[idx]=@list[idx].subseq(0...pos) return idx end
_fragment_discard_before(pos)
click to toggle source
# File lib/sequence/list.rb, line 169 def _fragment_discard_before(pos) idx=_lookup_idx(pos) pos-=@start_pos[idx] @list[idx]=@list[idx].subseq(pos..-1) return idx end
_lookup_idx(pos)
click to toggle source
def _lookup_idx
(pos)
low=0;high=@start_pos.size-1 while(high>low+1) mid=(low+high)/2 this_pos,next_pos=*@start_pos[mid,2] if pos<this_pos high=mid # - 1 ?? elsif pos<next_pos return mid elsif pos==next_pos return mid+1 else low=mid + 1 end end low
end
# File lib/sequence/list.rb, line 70 def _lookup_idx(pos) pos==size and return @list.size-1 assert((0...size)===pos) assert @start_pos.size==@list.size+1 low=0;high=@start_pos.size-1 assert @start_pos[low]<=pos assert @start_pos[high]>pos while(high>low+1) assert @start_pos[low]<=pos assert @start_pos[high]>pos mid=(low+high)/2 case pos<=>@start_pos[mid] when -1; high=mid when 0; break low=mid when 1; low=mid end end assert @start_pos[low]<=pos assert @start_pos[low+1]>pos low end
_pos=(pos)
click to toggle source
# File lib/sequence/list.rb, line 143 def _pos=pos @pos=pos assert((0..size)===pos) @current_idx= _lookup_idx(pos) end
_rebuild_idxs(start=1)
click to toggle source
# File lib/sequence/list.rb, line 40 def _rebuild_idxs(start=1) seed=@start_pos[0...start] seed.empty? and seed=[0] start==0 and start=1 @start_pos=(start..@list.size).inject(seed){|arr,i| arr<<arr.last+@list[i-1].size } #@start_pos.pop #maybe update @current_idx too? end
append(data)
click to toggle source
# File lib/sequence/list.rb, line 274 def append(data) if @list.last.overlaid? @list.last.append data return self end data=data.dup.to_sequence #data.instance_eval(&Overlaid) data.extend Overlaid @list<<data @start_pos<<@start_pos.last+data.size notify_change(self,@start_pos[-2], 0, data.size) self end
change_notification(cu,first,oldsize,newsize)
click to toggle source
# File lib/sequence/list.rb, line 29 def change_notification(cu,first,oldsize,newsize) idx=@list.each_with_index{|item,i| cu.equal? item and break i} diff=newsize-oldsize (idx+1...@start_pos.size).each{|i| @start_pos[i]+=diff } @pos=_adjust_pos_on_change(@pos, first,oldsize,newsize) @current_idx=_lookup_idx @pos notify_change(self,@start_pos[idx]+first,oldsize,newsize) end
eof?()
click to toggle source
# File lib/sequence/list.rb, line 153 def eof? @pos>=size end
holding() { |self| ... }
click to toggle source
# File lib/sequence/list.rb, line 111 def holding oldpos,oldidx=@pos,@current_idx begin yield self ensure @pos,@current_idx=oldpos,oldidx end end
holding!(&block)
click to toggle source
like holding
, but block is instance_eval'd in the seq.
# File lib/sequence/list.rb, line 132 def holding! &block oldpos,oldidx=@pos,@current_idx begin instance_eval self, &block ensure @pos,@current_idx=oldpos,oldidx end end
holding?() { |self| ... }
click to toggle source
like holding
, but position is reset only if block returns false or nil (or raises an exception).
# File lib/sequence/list.rb, line 122 def holding? oldpos,oldidx=@pos,@current_idx begin result=yield self ensure (@pos,@current_idx=oldpos,oldidx) unless result end end
modify(*args)
click to toggle source
Overlaid
=proc do
class<<self def overlaid?; true end def subseq(*) result=super result.instance_eval(& Overlaid) return result end end
end
# File lib/sequence/list.rb, line 195 def modify(*args) result=repldata=args.pop repllen=repldata.size # unless repldata.empty? repldata=repldata.dup.to_sequence #mark replacement data as overlaid #repldata.instance_eval(&Overlaid) repldata.extend Overlaid # end replseqs=[repldata] first,len,only1=_parse_slice_args(*args) if len.zero? and repllen.zero? notify_change self,first,len,repllen return result end f_idx=first.zero?? 0 : _lookup_idx(first-1) last_item_i=first+len-1 last_item_i=0 if last_item_i<0 l_idx=_lookup_idx(last_item_i) assert f_idx <= l_idx fragrest_f=first-@start_pos[i=_lookup_idx(first)] fragrest_l=first+len-@start_pos[l_idx] #@list[i] can be nil here... maybe because i==@list.size? assert fragrest_f <= @list[i].size # assert fragrest_l <= @list[l_idx].size unless l_idx == @list.size and fragrest_l.zero? #merge replacement data with adjacent seq(s) if also overlaid if fragrest_f.nonzero? #if inserted chunklet won't be empty replseqs.unshift( item=@list[i].subseq(0...fragrest_f) ) if item.respond_to? :overlaid? repldata.prepend item.all_data replseqs.shift end end if fragrest_l < @list[l_idx].size #if inserted chunklet won't be empty replseqs.push( item=@list[l_idx].subseq(fragrest_l..-1) ) if item.respond_to? :overlaid? repldata.append item.all_data replseqs.pop end end replseqs.delete_if{|cu| !cu or cu.empty? } #now remove those elements in between and #insert replacement data at the same point assert f_idx >= 0 assert l_idx >= 0 assert f_idx < @list.size assert l_idx <= @list.size assert f_idx <= l_idx @list[i..l_idx]=replseqs #base=f_idx.zero?? 0 : @start_idx[f_idx-1] #@start_idx[f_idx...l_idx]=[base+repldata.size] #rebuild indeces after altered part _rebuild_idxs(f_idx) @pos=_adjust_pos_on_change(@pos, first,len,result.size) @current_idx=_lookup_idx @pos notify_change(self,first,len,repllen) result end
prepend(data)
click to toggle source
# File lib/sequence/list.rb, line 287 def prepend(data) if @list.first.overlaid? @list.first.prepend data return self end data=data.dup.to_sequence #data.instance_eval(&Overlaid) data.extend Overlaid @list[0,0]=data #insert data.size into beginning of @start_pos sz=data.size @start_pos=@start_pos.map{|n| n+sz} @start_pos[0,0]=0 notify_change(self,0, 0, data.size) self end
read(len)
click to toggle source
# File lib/sequence/list.rb, line 105 def read(len) result=readahead(len) move result.size result end
readahead(len)
click to toggle source
# File lib/sequence/list.rb, line 92 def readahead(len) idx=_lookup_idx(pos) result=@list[idx][pos-@start_pos[idx],len] || new_data len-=result.size assert len>=0 (idx+1).upto(@list.size-1){|i| break(result+=@list[i][0,len]) if len<@list[i].size result+=@list[i].all_data len-=@list[i].size } result end
size()
click to toggle source
# File lib/sequence/list.rb, line 149 def size @start_pos.last end