lib/lru_redux/cache.rb in lru_redux-0.8.4 vs lib/lru_redux/cache.rb in lru_redux-1.1.0

- old
+ new

@@ -1,163 +1,108 @@ - - +# Ruby 1.9 makes our life easier, Hash is already ordered +# +# This is an ultra efficient 1.9 freindly implementation class LruRedux::Cache + def initialize(*args) + max_size, _ = args - # for high efficiency nodes in double linked list are stored in arrays - # [prev,key,val,next] - # - # This makes this much more annoying to code, but gives us a 5-10% edge + raise ArgumentError.new(:max_size) if max_size < 1 - def initialize(max_size) @max_size = max_size @data = {} - @head = nil - @tail = nil end - def max_size=(size) - raise ArgumentError.new(:max_size) if @max_size < 1 - @max_size = size - while pop_tail - # no op - end + def max_size=(max_size) + max_size ||= @max_size + + raise ArgumentError.new(:max_size) if max_size < 1 + + @max_size = max_size + + @data.shift while @data.size > @max_size end + def ttl=(_) + nil + end + def getset(key) - node = @data[key] - if node - move_to_head(node) - node[2] + found = true + value = @data.delete(key){ found = false } + if found + @data[key] = value else - self[key] = yield + result = @data[key] = yield + @data.shift if @data.length > @max_size + result end end def fetch(key) - node = @data[key] - if node - move_to_head(node) - node[2] + found = true + value = @data.delete(key){ found = false } + if found + @data[key] = value else yield if block_given? end end def [](key) - node = @data[key] - if node - move_to_head(node) - node[2] + found = true + value = @data.delete(key){ found = false } + if found + @data[key] = value + else + nil end end def []=(key,val) - node = @data[key] - if node - move_to_head(node) - node[2] = val - else - @data[key] = add_to_head(key,val) - pop_tail - end + @data.delete(key) + @data[key] = val + @data.shift if @data.length > @max_size val end def each - a = to_a - a.each do |pair| + array = @data.to_a + array.reverse!.each do |pair| yield pair end end - def each_unsafe - n = @head - if n - while n - yield [n[1], n[2]] - n = n[0] - end - end - end + # used further up the chain, non thread safe each + alias_method :each_unsafe, :each def to_a - a = [] - self.each_unsafe do |k,v| - a << [k,v] - end - a + array = @data.to_a + array.reverse! end def delete(key) - node = @data.delete(key) + @data.delete(key) + end - return unless node + alias_method :evict, :delete - prev = node[0] - nex = node[3] - - nex ? nex[0] = prev : @head = prev - prev ? prev[3] = nex : @tail = nex - - node[2] + def key?(key) + @data.key?(key) end + alias_method :has_key?, :key? + def clear @data.clear - @head = @tail = nil end def count @data.size end - # for cache validation only, ensures all is sound - def valid? - count = 0 - self.each_unsafe do |k,v| - return false if @data[k][2] != v - count += 1 - end - count == @data.size - end - protected - def add_to_head(key,val) - if @head.nil? - @tail = @head = [nil,key,val,nil] - else - node = [@head,key,val,nil] - @head = @head[3] = node - end - end - - def move_to_head(node) - return unless @head && node[1] != @head[1] - - prev = node[0] - nex = node[3] - - if prev - prev[3] = nex - else - @tail = nex - end - - if nex - nex[0] = prev - end - - @head[3] = node - node[0] = @head - @head = node - end - - def pop_tail - if @data.length > @max_size - @data.delete(@tail[1]) - @tail = @tail[3] - @tail[0] = nil - true - end + # for cache validation only, ensures all is sound + def valid? + true end end