class PackedModel::List
Public Class Methods
new(row_class, values=nil)
click to toggle source
# File lib/packed_model/list.rb, line 5 def initialize(row_class, values=nil) raise InvalidPackedModelException.new("row_class must be fixed width") unless row_class.fixed_width? @row_class = row_class values.force_encoding(Encoding::BINARY) if values.respond_to?(:force_encoding) @buffer = values end
Public Instance Methods
<<(row)
click to toggle source
# File lib/packed_model/list.rb, line 25 def <<(row) row.changed! rows << row end
[](idx)
click to toggle source
the data in each row is only unpacked when it is accessed from here
# File lib/packed_model/list.rb, line 13 def [](idx) if (row = rows[idx]).is_a?(String) row = rows[idx] = @row_class.new(row) end row end
[]=(idx, row)
click to toggle source
# File lib/packed_model/list.rb, line 20 def []=(idx, row) row.changed! rows[idx] = row end
bytesize()
click to toggle source
# File lib/packed_model/list.rb, line 84 def bytesize row_bytesize * size end
each() { |self| ... }
click to toggle source
# File lib/packed_model/list.rb, line 88 def each self.size.times do |idx| yield self[idx] end end
find_in_buffer(val)
click to toggle source
to search the buffer the first field must be a marker and the 2nd is the what you are searching for Example: class TestSearchableModel < PackedModel::Base
attribute :magic, :type => :marker, :value => 20130502 attribute :id, :type => :integer attribute :name, :type => :char, :size => 20 end
# File lib/packed_model/list.rb, line 70 def find_in_buffer(val) return nil unless @buffer @results ||= {} return @results[val] if @results.has_key?(val) index = @buffer.index search_string(val) return (@results[val] = nil) unless index index = index / row_bytesize @results[val] = self[index] end
pack()
click to toggle source
# File lib/packed_model/list.rb, line 35 def pack return repack if @must_repack return @buffer unless @rows @buffer ||= ''.force_encoding(Encoding::BINARY) start = 0 @rows.each_with_index do |row, idx| # only updated dirty rows if ! row.is_a?(String) && row.changed? @buffer[start...(start+row_bytesize)] = row.pack row.not_changed! end start += row_bytesize end @buffer end
remove(idx)
click to toggle source
# File lib/packed_model/list.rb, line 30 def remove(idx) @must_repack = true rows[idx] = nil end
repack()
click to toggle source
repacks the buffer
# File lib/packed_model/list.rb, line 52 def repack @buffer = ''.force_encoding(Encoding::BINARY) self.each do |row| next unless row @buffer << row.pack end remove_instance_variable "@rows" remove_instance_variable("@must_repack") if defined?(@must_repack) remove_instance_variable("@results") if defined?(@results) @buffer end
size()
click to toggle source
# File lib/packed_model/list.rb, line 80 def size rows.size end
Private Instance Methods
row_bytesize()
click to toggle source
# File lib/packed_model/list.rb, line 117 def row_bytesize @row_class.bytesize end
rows()
click to toggle source
# File lib/packed_model/list.rb, line 110 def rows if ! defined?(@rows) @rows = @buffer ? unpack(@buffer) : [] end @rows end
search_string(val)
click to toggle source
# File lib/packed_model/list.rb, line 121 def search_string(val) marker_field = @row_class.fields[0] key_field = @row_class.fields[1] [marker_field[:value], val].pack "#{marker_field[:pack_directive]}#{key_field[:pack_directive]}" end
unpack(str)
click to toggle source
doesn’t really unpack the data into models, just creates an array of pointers into the buffer data is not unpacked unless it is accessed
# File lib/packed_model/list.rb, line 98 def unpack(str) raise InvalidDataException.new("invalid string for list") unless (str.bytesize % row_bytesize) == 0 start = 0 [].tap do |data| (str.bytesize / row_bytesize).times do data << str[start...(start+row_bytesize)] # essentially we are creating C style pointers into the string at certain locations start += row_bytesize end end end