class Sequence

(.… need to steal more features from Array, String, File, StringScanner, Enumerable?, like:)

pack/unpack

match/matchback

Copyright (C) 2006, 2011 Caleb Clausen Distributed under the terms of Ruby's license.

require 'sequence/split'

Copyright (C) 2006,2008, 2011 Caleb Clausen Distributed under the terms of Ruby's license.

Copyright (C) 2006, 2011  Caleb Clausen
Distributed under the terms of Ruby's license.

require 'sequence'

Copyright (C) 2006,2008, 2011 Caleb Clausen Distributed under the terms of Ruby's license.

WeakRefSet implements an unordered collection of weak references to objects. These references don't prevent garbage collection on these objects. As these objects are thrown away so does their entry in a WeakRefSet. Immmediate objects are not handled by this class (and wouldn't be useful).

Constants

SubSequence
VERSION

Attributes

last_match[RW]
maxmatchlen[W]

Public Class Methods

[](*x) click to toggle source
# File lib/sequence.rb, line 61
def [](*x) new(*x) end
new() click to toggle source
# File lib/sequence.rb, line 41
def initialize; abstract end
Also aliased as: original__new
new(seq) click to toggle source
# File lib/sequence.rb, line 48
def new(seq)
  case seq
    when File,IO,Array,String,Enumerable
      seq.to_sequence
    else
      if seq.respond_to? :to_str
        seq.to_str.to_sequence
      else
        raise ArgumentError
      end
  end
end
original__new()
Alias for: new

Public Instance Methods

+(other) click to toggle source

Returns a new position increased by len (positive or negative).

# File lib/sequence.rb, line 464
def +(other)
  if ::Sequence===other
    List[self, other]
  else
    position(pos+other)
  end
end
-(other) click to toggle source

if passed an integer arg, return a new position decreased by len. if passed

a position, return the distance (number
or elements) from +other+ (a #position) to +self+.  This can be +, -, or 0.
# File lib/sequence.rb, line 456
def -(other)
  if position?(other)
    pos-other.pos
  else
    position(pos-other)
  end
end
<<(x) click to toggle source
# File lib/sequence.rb, line 639
def <<(x) push x; return self end
[](*a) click to toggle source
# File lib/sequence.rb, line 598
def [](*a) slice(*a) end
[]=(*a) click to toggle source
# File lib/sequence.rb, line 616
def []=(*a) modify(*a) end
_adjust_pos_on_change(pos,first,oldsize,newsize) click to toggle source
# File lib/sequence.rb, line 679
  def _adjust_pos_on_change pos,first,oldsize,newsize
#      assert newsize != oldsize
    if pos>=first+oldsize
      oldsize.zero? and pos==first and return pos
      pos+newsize-oldsize
    elsif pos>first
      first
    else pos
    end
  end
_default_maxmatchlen() click to toggle source
# File lib/sequence.rb, line 243
def _default_maxmatchlen; 1024 end
_normalize_pos(pos,size=self.size) click to toggle source
# File lib/sequence.rb, line 548
def _normalize_pos(pos,size=self.size)
  if pos<0 
    pos+=size
    pos<0 and pos=0
  elsif pos>size
    pos=size
  end

  assert((0..size)===pos)
  pos
end
_parse_slice_args(*args) click to toggle source
# File lib/sequence.rb, line 560
def _parse_slice_args(*args)
  asize=args.size
  assert !closed?
  size=self.size
  case r=args.first
    when Range
      asize==1 or raise ArgumentError
      first,last=r.first,r.last
      first=_normalize_pos(first,size)
      last=_normalize_pos(last,size)
      len=last-first
      r.exclude_end? or len+=1
    when Integer
      asize<=2 or raise ArgumentError
      first=_normalize_pos(r,size)
      len=args[1] || (only1=1)
    when nil
      asize==0 or raise ArgumentError
      first=nil
      len=only1=1
    else raise ArgumentError
  end
  return first,len,only1
end
_pos=(p) click to toggle source
# File lib/sequence.rb, line 344
def _pos=(p)
  abstract
end
all_data() click to toggle source
# File lib/sequence.rb, line 123
def all_data
  holding_position{|posi|
    posi.begin!
    posi.read!
  }
end
append(stuff) click to toggle source

push/unshift in stringlike/arraylike

# File lib/sequence.rb, line 643
def append stuff
  insert(size, stuff)
  self
end
begin() click to toggle source

Return a new position for the beginning.

# File lib/sequence.rb, line 481
def begin
  position(0)
end
begin!() click to toggle source

go to beginning

# File lib/sequence.rb, line 490
def begin!
  self._pos=0
end
check(pat) click to toggle source
# File lib/sequence.rb, line 207
def check(pat)           holding{scan(pat)}    end
check_until(pat) click to toggle source
# File lib/sequence.rb, line 211
def check_until(pat)     holding{scan_until(pat)}    end
checkback(pat) click to toggle source
# File lib/sequence.rb, line 215
def checkback(pat)       holding{scanback(pat)}    end
checkback_until(pat) click to toggle source
# File lib/sequence.rb, line 219
def checkback_until(pat) holding{scanback_until(pat)} end
close() click to toggle source

Close the sequence. This will also close/invalidate every child position or derived sequence.

# File lib/sequence.rb, line 429
def close
  defined? @change_listeners and @change_listeners.each { |p|
    Sequence===p and p.close
  }
  # this should make just about any operation fail
  instance_variables.each { |v| remove_instance_variable(v) }
  nil
end
closed?() click to toggle source

Is this sequence closed?

# File lib/sequence.rb, line 438
def closed?
  instance_variables.empty?
end
delete(*args) click to toggle source
# File lib/sequence.rb, line 618
def delete(*args) #index|range, len
  modify( *args<<new_data)
  nil
end
each() { |value| ... } click to toggle source

Performs each just to make this class Enumerable. self is returned (or the break value if the code does a break).

# File lib/sequence.rb, line 712
def each # :yield: value
  holding {
    begin!
    until eof?
      yield read1
    end or self
  }
end
empty?() click to toggle source

is there any data in the sequence?

# File lib/sequence.rb, line 534
def empty?
  size==0
end
end() click to toggle source

Return a new position for the end.

# File lib/sequence.rb, line 485
def end
  position(size)
end
end!() click to toggle source

go to end

# File lib/sequence.rb, line 494
def end!
  self._pos=size
end
eof?() click to toggle source

are we at past the end of the sequence data, with no more data ever to arrive?

# File lib/sequence.rb, line 529
def eof?
  abstract
end
exist?(pat) click to toggle source
# File lib/sequence.rb, line 212
def exist?(pat)          holding{skip_until(pat)}    end
existback?(pat) click to toggle source
# File lib/sequence.rb, line 220
def existback?(pat)      holding{skipback_until(pat) }end
first() click to toggle source

return first element of data

# File lib/sequence.rb, line 539
def first
  slice 0
end
goto(p) click to toggle source

go to an absolute position; identical to pos=

# File lib/sequence.rb, line 340
def goto p
  self.pos= p
end
holding() { |self| ... } click to toggle source

hold current position while executing a block. The block is passed the current sequence as its parameter. you can move the position around or call methods like read that do it, but after the block returns, the position is reset to the original location. The return value is the result of the block.

# File lib/sequence.rb, line 259
def holding
  oldpos=pos
  begin
    yield self
  ensure
    self.pos=oldpos
  end
end
holding!(&block) click to toggle source

like holding, but block is instance_eval'd in the sequence.

# File lib/sequence.rb, line 280
def holding! &block
  oldpos=pos
  begin
    instance_eval self, &block
  ensure
    self.pos=oldpos
  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.rb, line 270
def holding?
  oldpos=pos
  begin
    result=yield self
  ensure
    (self.pos=oldpos) unless result
  end
end
holding_position() { |self| ... } click to toggle source
# File lib/sequence.rb, line 290
def holding_position
  pos=position
  begin
    result=yield self
  ensure
    self.position=pos
    pos.close
  end
end
holding_position!(&block) click to toggle source
# File lib/sequence.rb, line 310
def holding_position! &block
  pos=position
  begin
    result=instance_eval self,&block
  ensure
    self.position=pos
    pos.close
  end
end
holding_position?() { |self| ... } click to toggle source
# File lib/sequence.rb, line 300
def holding_position?
  pos=position
  begin
    result=yield self
  ensure
    self.position=pos unless result
    pos.close
  end
end
insert(index, replacedata) click to toggle source
# File lib/sequence.rb, line 623
def insert index, replacedata
  modify index,0, replacedata
end
last() click to toggle source

return last element of data

# File lib/sequence.rb, line 544
def last
  slice( -1)
end
length() click to toggle source
# File lib/sequence.rb, line 526
def length; size end
match?(pat) click to toggle source
# File lib/sequence.rb, line 208
def match?(pat)          holding{skip(pat)}    end
matchback?(pat) click to toggle source
# File lib/sequence.rb, line 216
def matchback?(pat)      holding{skipback(pat)}    end
maxmatchlen(backwards) click to toggle source
# File lib/sequence.rb, line 245
def maxmatchlen(backwards)
  size=self.size

  list=[ _default_maxmatchlen,
         backwards ? pos : size-pos%size
  ]
  list.push @maxmatchlen if defined? @maxmatchlen
  list.min
end
modify(*args) click to toggle source

Similar to slice except data is written. index and len have the same meaning as they do in slice. len elements are deleted and replacedata is inserted. replacedata is a single item if len is ommitted and 1st param is Fixnum

# File lib/sequence.rb, line 613
def modify(*args) #index|range, len, replacedata
  abstract
end
more_data?() click to toggle source

is there any more data after the position?

# File lib/sequence.rb, line 511
def more_data?
  #!eof?
  (size-pos).nonzero?
end
move(len) click to toggle source

move position len elements, relative to the current position. A negative len will go in reverse. The (positive) amount actually moved is returned (<len if reached beginning/end).

# File lib/sequence.rb, line 350
def move(len)
  oldpos=pos
  newpos=oldpos+len
  newpos<0 and newpos=0
  goto newpos
  return (pos-oldpos).abs
end
move!(reverse=false) click to toggle source

move to end of the remaining elements. reverse=true to move to beginning instead of end The amount moved is returned.

# File lib/sequence.rb, line 360
def move!(reverse=false)
  reverse ? begin! : end!
end
nearbegin(len,at=pos) click to toggle source
# File lib/sequence.rb, line 500
def nearbegin(len,at=pos)
  at<=len
end
nearend(len,at=pos) click to toggle source
# File lib/sequence.rb, line 506
def nearend(len,at=pos)
  at+len>=size
end
notify_change(*args) click to toggle source
# File lib/sequence.rb, line 697
def notify_change *args   #seq, first, oldsize, newsize
  args[0]=self
  defined? @change_listeners and @change_listeners.each{|obj|
    obj.change_notification(*args)
  }
end
on_change_notify(obj) click to toggle source
# File lib/sequence.rb, line 690
def on_change_notify obj
  Symbol===obj and raise ArgumentError
  obj.respond_to? :change_notification or raise ArgumentError
  @change_listeners||=WeakRefSet[]
  @change_listeners<<obj
end
overwrite(index, replacedata) click to toggle source
# File lib/sequence.rb, line 627
def overwrite index, replacedata
  modify index,replacedata.size, replacedata
end
pop(count=nil) click to toggle source
# File lib/sequence.rb, line 631
def pop count=nil
  slice!(count ? -count...size : -1)
end
pos() click to toggle source

number of elements from the beginning (0 is at the beginning).

# File lib/sequence.rb, line 322
def pos()
    abstract
end
pos=(p) click to toggle source

Set pos to be p. When p is negative, it is set from the end.

# File lib/sequence.rb, line 334
def pos=(p)
    position?(p) and p=p.pos unless Integer===p
    self._pos=_normalize_pos p
end
pos?(p) click to toggle source

this checks to see if p is a valid numeric position.

# File lib/sequence.rb, line 328
def pos?(p)
  sz=size
  (-sz..sz)===p
end
position(_pos=pos) click to toggle source

position returns a Sequence::Position to represent a location within this sequence. The argument allows you to specify a numeric location for the position; default is currrent position. If the element that a Position is anchored to is deleted, that Position may become invalid or have an unknown behavior.

# File lib/sequence.rb, line 392
def position(_pos=pos)
  Position.new(self,_pos)
end
position=(p) click to toggle source

Set the position to a Position p (from position).

# File lib/sequence.rb, line 396
def position=(p)
  self.pos = p.pos
  self.prop(nil,p.prop)
  p
end
position?(p) click to toggle source

this queries whether a particular position p is valid (is a child or self). numeric positions and also be tested

# File lib/sequence.rb, line 404
def position?(p)
  case p
  when Integer; (-size..size)===p
  when Position; equal? p.data
  else equal? p
  end
end
pred() click to toggle source

Return a new position for previous location or nil if we are at the beginning.

# File lib/sequence.rb, line 477
def pred
  self-1 unless pos.zero?
end
prepend(stuff) click to toggle source
# File lib/sequence.rb, line 648
def prepend stuff
  insert(0, stuff)
  self
end
prop(name[,value]) click to toggle source

Get (if no value) and set properties. Normally, name should be a symbol. If name is nil, it wil get/set using a hash representing all of the properties.

# File lib/sequence.rb, line 367
def prop(name=nil,*value) # :args: (name[,value])
  if name.nil?
    if value.size.zero?
      defined?(@prop) &&@prop&&@prop.clone
    else
      if (value = value[0]).nil?
        defined?(@prop) &&@prop&&remove_instance_variable(:@prop)
      else
        (@prop||={}).replace(value)
      end
    end
  else
    if value.size.zero?
      defined?(@prop) &&@prop&&@prop[name]
    else
      (@prop||={})[name] = value[0]
    end
  end
end
read(len) click to toggle source
attempt to read up to +len+ elements. the  position is left just after the data read.
#read may return less than the whole requested amount if less data than requested in

len is available. This can happen at end of file or if more data is simply unavailable currently (ie with a Sequence::IO). Don't assume that getting less than you requested means you're at end of file; use eof? to test for that instead.

# File lib/sequence.rb, line 92
def read(len)
  abstract
end
read!(reverse=false) click to toggle source

read the remaining elements. if reverse, read everything behind position

# File lib/sequence.rb, line 115
def read!(reverse=false)
  if reverse
    readback pos
  else
    read rest_size
  end
end
read1() click to toggle source

read next element or nil if eof and advance position

# File lib/sequence.rb, line 67
def read1
  (read 1)[0]
end
readahead(len) click to toggle source

like read, but position is left alone.

# File lib/sequence.rb, line 97
def readahead(len)
  holding{read(len)}
end
readahead1() click to toggle source

read element after the pos or nil if eof, leaving position alone

# File lib/sequence.rb, line 77
def readahead1
  slice pos
end
readback(len) click to toggle source

read data behind the current position, leaving position just before the data read.

# File lib/sequence.rb, line 108
def readback(len)
  len>pos and len=pos
  readahead move( -len )
end
readback1() click to toggle source

read previous element or nil if start of input and move position back

# File lib/sequence.rb, line 72
def readback1
  (readback 1)[0]
end
readbehind(len) click to toggle source

read data behind the current position, leaving position unchanged

# File lib/sequence.rb, line 102
def readbehind(len)
  len>pos and len=pos
  read move( -len)
end
readbehind1() click to toggle source

read element before the pos or nil if start of input, leaving position alone

# File lib/sequence.rb, line 82
def readbehind1
  slice pos-1 unless pos.zero?
end
rest_size() click to toggle source
# File lib/sequence.rb, line 325
def rest_size; size - pos end
reversed() click to toggle source

make a new sequence that reverses the order of data. reversed and parent sequence share data.

# File lib/sequence.rb, line 423
def reversed
  Reversed.new self
end
shift(count=nil) click to toggle source
# File lib/sequence.rb, line 635
def shift count=nil
  slice!(count ? 0...count : 0 )
end
size() click to toggle source

Returns the number of elements.

# File lib/sequence.rb, line 523
def size
  abstract
end
skip(pat) click to toggle source

def scan(pat)

abstract

end

def scan_until(pat)

abstract

end def scanback(pat)

abstract

end

def scanback_until(pat)

abstract

end

def match(pat)

abstract

end

def matchback(pat)

abstract

end

# File lib/sequence.rb, line 206
def skip(pat)            match=  scan(pat) and match.length    end
skip_literal(lits) click to toggle source
# File lib/sequence.rb, line 222
def skip_literal(lits)
  sz=lits.size
  lits==readahead(sz) and move sz
end
Also aliased as: skip_literals
skip_literals(lits)
Alias for: skip_literal
skip_until(pat) click to toggle source
# File lib/sequence.rb, line 210
def skip_until(pat)      match=  scan_until(pat) and match.length    end
skip_until_literal(lits) click to toggle source
# File lib/sequence.rb, line 228
def skip_until_literal(lits)
  sz=lits.size
  first=lits[0]
  holding?{
  until eof?
    skip_until(first)
    lits==readahead(sz) and break pos
  end
  }
end
Also aliased as: skip_until_literals
skip_until_literals(lits)
Alias for: skip_until_literal
skipback(pat) click to toggle source
# File lib/sequence.rb, line 214
def skipback(pat)        match=  scanback(pat) and match.length    end
skipback_until(pat) click to toggle source
# File lib/sequence.rb, line 218
def skipback_until(pat)  match=  scanback_until(pat) and match.length end
slice(*args) click to toggle source

Provides random access for the sequence like what is in Array/String. index can be nil (start at the current location) or a numeric (for pos=) or a range. len can be nil (get a single element) or the number of elements to read (positive or negative). The sequence's position is left alone.

# File lib/sequence.rb, line 590
def slice(*args) #index|range=nil,len=nil
  first,len,only1=_parse_slice_args( *args)
  pos==first and first=nil
  holding {
    self.pos = first if first
    only1 ? read1 : read(len)
  }
end
slice!(*args) click to toggle source

Like slice except the element(s) are deleted.

# File lib/sequence.rb, line 602
def slice!(*args) #index|range, len
  first,len,only1=_parse_slice_args( *args)
  result=slice(first,len)
  delete(first,len)
  only1 ? result.first : result
end
slice1(idx) click to toggle source
# File lib/sequence.rb, line 599
def slice1(idx) slice(idx) end
slice1!(idx) click to toggle source
# File lib/sequence.rb, line 608
def slice1!(idx) slice!(idx) end
subseq(*args) click to toggle source

make a new sequence out of a subrange of current sequence data. the subseq and parent seq share data, so changes in one will be reflected in the other.

# File lib/sequence.rb, line 415
def subseq(*args)
  assert !closed?
  first,len,only1=_parse_slice_args(*args)
  SubSeq.new(self,first,len)
end
succ() click to toggle source

Return a new position for next location or nil if we are at the end.

# File lib/sequence.rb, line 473
def succ
  self+1 unless eof?
end
to_sequence() click to toggle source
# File lib/sequence.rb, line 42
def to_sequence; self end
was_data?() click to toggle source

has any data been seen so far, or are we still at the beginning?

# File lib/sequence.rb, line 517
def was_data?
  pos.nonzero?
end
write(data) click to toggle source
# File lib/sequence.rb, line 653
def write(data)
  assert oldpos=pos
  writeahead(data)
  assert oldpos==pos
  move data.size
end
writeahead(data) click to toggle source
# File lib/sequence.rb, line 667
def writeahead(data)
  raise ArgumentError, "attempted overwrite at end of #{self}" if data.size>rest_size
     overwrite(pos,data)
  data.size
end
writeback(data) click to toggle source
# File lib/sequence.rb, line 660
def writeback(data)
  assert oldpos=pos
  writebehind(data)
  assert oldpos==pos
  move( -data.size)
end
writebehind(data) click to toggle source
# File lib/sequence.rb, line 673
def writebehind(data)
  raise ArgumentError, "attempted overwrite at begin of #{self}" if data.size>pos
     overwrite(pos-data.size,data)
  data.size
end