Skip to content

Instantly share code, notes, and snippets.

@wader
Created January 25, 2014 16:57
Show Gist options
  • Save wader/8619462 to your computer and use it in GitHub Desktop.
Save wader/8619462 to your computer and use it in GitHub Desktop.
Sparse ruby IO class
class SparseFile < IO
def initialize(ranges, total_length, fill = "\0")
@ranges = ranges
@total_length = total_length
@position = 0
@fill = fill
end
def rewind
@position = 0
end
# read([length [, outbuf]]) → string, outbuf, or nil
# Reads length bytes from the I/O stream.
def read(length=-1, outbuf=nil)
buf = []
buf_length = 0
# rest of file
length = @total_length-@position if length == -1
length = length - @position if @position+length > @total_length
lenght = 0 if length < 0
# 01234567890123456789
# ABCDEF GHIJK
# [ ] before
# [ ] half
# [ ] full
# [ ] combined
# [ ] half
@ranges.each do |offset, buffer|
# to far
if @position+length < offset
break
end
# enough
if length == 0
break
end
# skip
if offset+buffer.length < @position
next
end
# pad before
if @position < offset
n = offset-@position
buf.push(@fill*n)
length -= n
@position += n
end
o = @position-offset
n = length > buffer.length-o ? buffer.length-o : length
buf.push(buffer[o,n])
length -= n
@position += n
end
# pad after
buf.push(@fill*(length-buf_length)) if buf_length < length
@position += length
buf.join
end
# seek(amount, whence=IO::SEEK_SET) -> 0
# Seeks to a given offset anInteger in the stream according to the value of whence:
def seek(amount, whence=IO::SEEK_SET)
@position = case whence
when IO::SEEK_CUR then @position+amount
when IO::SEEK_END then @total_length+amount
when IO::SEEK_SET then amount
end
@position = @total_length if @position > @total_length
@position = 0 if @position < 0
0
end
# def method_missing(m, *args, &block)
# puts "missing", m
# end
end
if false
r = SparseFile.new([
[5, "abcdef"],
[13, "ghijk"]
], 20, "-")
expected = [
"---",
"--ab",
"cde",
"f--gh",
"ijk-"
]
actual = [
r.read(3),
r.read(4),
r.read(3),
r.read(5),
r.read(4)
]
puts
puts expected
puts
puts actual
puts
r.rewind
puts r.read(20)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment