class Huffnpuff

Constants

CMP
VERSION

Public Class Methods

get_system_string_from_histogram(ary, rat = 0.61) click to toggle source
# File lib/huffnpuff.rb, line 41
def self.get_system_string_from_histogram(ary, rat = 0.61)
  raise "histogram array must be reverse sorted with values >= 1" unless histogram_array_valid?(ary)
  raise "parameter 2 must be between 0.1 and 0.9" unless ((rat >= 0.1) && (rat <= 0.9))
  sys = []
  top = (rat * 4096.0).to_i
  n = ary.count - 1
  tar = (ary[0] * top) >> 12
  cnt = 1
  n.times do |idx|
    if ary[idx+1] <= tar
      sys.push cnt
      cnt = 1
      tar = (ary[idx+1] * top) >> 12
    else
      cnt += 1
    end
  end
  sys.push cnt
  ary = []
  borrow = 0
  sys.each do |num|
    num -= borrow
    bin_size = 1 << (num-1).bit_length
    ary.push bin_size
    borrow = bin_size - num      
  end
  pre = ""
  if ary.count==1  # don't bother ... all same
    return "x" * (ary.first.bit_length - 1)
  end
  sys = []
  ary.each do |num|
    str = pre + "0" + "x" * (num.bit_length-1)
    pre += "1"
    sys.push str
  end
  sys.sort! &CMP
  sys.join(':')
end
histogram_array_valid?(ary) click to toggle source
# File lib/huffnpuff.rb, line 5
def self.histogram_array_valid?(ary)
  return false if ary.empty?
  ary.each do |elm|
    return false unless elm.kind_of? Integer
    return false if elm <= 0
  end
  return false unless ary == ary.sort.reverse
  true
end
new(sys, fifo, dat = []) click to toggle source
# File lib/huffnpuff.rb, line 84
def initialize(sys, fifo, dat = [])
  @data = dat
  @fifo = fifo
  systemize!(sys)
end
validate_system_string(str) click to toggle source
# File lib/huffnpuff.rb, line 15
def self.validate_system_string(str)
  ary = str.split(':')
  raise "singular bin not valid" if 1==ary.count
  ary.each do |bin|
    raise "empty bin definition" if bin.empty?
    raise "preamble missing: must start with 1 or 0" unless (bin[0]=='0' || bin[0]=='1')
    xmode = false
    bin.each_char do |ch|
      if xmode
        raise "illegal char following 'x': [#{ch}]" unless 'x'==ch
      else
        if ch=='x'
          xmode = true
        elsif ch=='0'
        elsif ch=='1'
        else
          raise "invalid symbol [#{ch}]"
        end
      end
    end
  end
  true
end

Public Instance Methods

get() click to toggle source

ok, we have a problem … the MSB is the preamble

# File lib/huffnpuff.rb, line 159
def get
  idx = 0
  @ary.each do |ii|
    pre = @fifo.get(ii.first.length)  # not enough bits to address data
    return nil if pre.nil?
    if(pre==ii.first.to_i(2))
      if(0==ii[1]) # only one, no x's
        return @data[ii[2]]
      else
        off = @fifo.get(ii[1])
        if off.nil?
          @fifo.unget(ii[1]+ii.first.length) # not enough bits to address data
          return nil
        end
        return @data[off + ii[2]]
      end
    else # put back to try another system
      @fifo.unget(ii.first.length)  
    end
  end
  return nil    
end
max() click to toggle source
# File lib/huffnpuff.rb, line 92
def max
  @max
end
min() click to toggle source
# File lib/huffnpuff.rb, line 89
def min
  @min
end
push(item) click to toggle source
# File lib/huffnpuff.rb, line 138
def push(item)
  raise "can't excede system size of #{@size}" if @data.size >= @size
  @data.push item
end
push_each(item) click to toggle source
# File lib/huffnpuff.rb, line 143
def push_each(item)
  if item.respond_to? :each
    item.each do |elm|
      push elm
    end
  elsif item.respond_to? :each_char
    item.each_char do |ch|
      push ch
    end
  else # punt
    push item
  end
end
size() click to toggle source
# File lib/huffnpuff.rb, line 95
def size
  @size
end
sys() click to toggle source
# File lib/huffnpuff.rb, line 99
def sys()
  @sys
end
systemize!(sys) click to toggle source
# File lib/huffnpuff.rb, line 103
def systemize!(sys)
  @ary = []
  if sys.kind_of? String
    @sys = sys
    ary = sys.split(':')
  elsif sys.kind_of? Array
    ary = sys
    @sys = ary.join(':')
  else
    raise "imcompatible type first parameter"
  end
  self.class.validate_system_string(@sys)
  off = 0
  @min = 2 ** 10000
  @max = 0
  ary.each do |ii|
    pos = ii.index('x')
    if pos.nil?
      @ary.push [ii,0, off]
      off += 1
      sz = ii.length
      @min = sz < @min ? sz : @min
      @max = sz > @max ? sz : @max
    else
      xcount = ii.length - pos
      @ary.push [ii[(0..(pos-1))],xcount,off]
      off += 2 ** xcount
      sz = xcount + ii[(0..(pos-1))].length
      @min = sz < @min ? sz : @min
      @max = sz > @max ? sz : @max
    end
  end
  @size = off  
end