Buffered stream.
EXAMPLE 1 – an IO.
class MyBuf < StreamBuf # Do initialize myself before a super class. Super class might call my # method 'read'. (Could be awful for C++ user. :-) def initialize(s) @s = s super() end # define my own 'read' method. # CAUTION: Returning nil means EnfOfStream. def read(size) @s.read(size) end # release buffers. in Ruby which has GC, you do not have to call this... def terminate @s = nil super() end end buf = MyBuf.new(STDIN) my_str = '' p buf[0, 0] # => '' (null string) p buf[0] # => 97 (char code of 'a') p buf[0, 1] # => 'a' my_str = buf[0, 5] p my_str # => 'abcde' (5 chars) p buf[0, 6] # => "abcde\n" (6 chars) p buf[0, 7] # => "abcde\n" (6 chars) p buf.drop(3) # => 3 (dropped chars) p buf.get(0, 2) # => 'de' (2 chars) p buf.is_eos? # => false (is not EOS here) p buf.drop(5) # => 3 (dropped chars) p buf.is_eos? # => true (is EOS here) p buf[0] # => nil (is EOS here)
EXAMPLE 2 – String.
This is a conceptual example. No pros with this.
class StrBuf < StreamBuf
def initialize(s)
@str = s
@idx = 0
super()
end
def read(size)
str = @str[@idx, size]
@idx += str.size
str
end
end
WARN: Do not instantiate this class directly. Define your own class which derives this class and define 'read' instance method.
# File csv.rb, line 888
def initialize
@buf_list = []
@cur_buf = @buf_tail_idx = -1
@offset = 0
@is_eos = false
add_buf
@cur_buf = @buf_tail_idx
end
get a char or a partial string from the stream. idx: index of a string to specify a start point of a string to get. unlike String instance, idx < 0 returns nil. n: size of a string to get. returns char at idx if n == nil. returns a partial string, from idx to (idx + n) if n != nil. at EOF, the string size could not equal to arg n.
# File csv.rb, line 803
def [](idx, n = nil)
if idx < 0
return nil
end
if (idx_is_eos?(idx))
if n and (@offset + idx == buf_size(@cur_buf))
# Like a String, 'abc'[4, 1] returns nil and
# 'abc'[3, 1] returns '' not nil.
return ''
else
return nil
end
end
my_buf = @cur_buf
my_offset = @offset
next_idx = idx
while (my_offset + next_idx >= buf_size(my_buf))
if (my_buf == @buf_tail_idx)
unless add_buf
break
end
end
next_idx = my_offset + next_idx - buf_size(my_buf)
my_buf += 1
my_offset = 0
end
loc = my_offset + next_idx
if !n
return @buf_list[my_buf][loc] # Fixnum of char code.
elsif (loc + n - 1 < buf_size(my_buf))
return @buf_list[my_buf][loc, n] # String.
else # should do loop insted of (tail) recursive call...
res = @buf_list[my_buf][loc, BufSize]
size_added = buf_size(my_buf) - loc
if size_added > 0
idx += size_added
n -= size_added
ret = self[idx, n]
if ret
res << ret
end
end
return res
end
end
drop a string from the stream. returns dropped size. at EOF, dropped size might not equals to arg n. Once you drop the head of the stream, access to the dropped part via [] or get returns nil.
# File csv.rb, line 854
def drop(n)
if is_eos?
return 0
end
size_dropped = 0
while (n > 0)
if !@is_eos or (@cur_buf != @buf_tail_idx)
if (@offset + n < buf_size(@cur_buf))
size_dropped += n
@offset += n
n = 0
else
size = buf_size(@cur_buf) - @offset
size_dropped += size
n -= size
@offset = 0
unless rel_buf
unless add_buf
break
end
@cur_buf = @buf_tail_idx
end
end
end
end
size_dropped
end
protected method 'read' must be defined in derived classes. CAUTION: Returning a string which size is not equal to 'size' means EnfOfStream. When it is not at EOS, you must block the callee, try to read and return the sized string.
# File csv.rb, line 907
def read(size) # raise EOFError
raise NotImplementedError.new('Method read must be defined in a derived class.')
end