lib/rufus/lru.rb in rufus-lru-1.0.5 vs lib/rufus/lru.rb in rufus-lru-1.0.7

- old
+ new

@@ -1,7 +1,7 @@ #-- -# Copyright (c) 2007-2012, John Mettraux, jmettraux@gmail.com +# Copyright (c) 2007-2016, John Mettraux, jmettraux@gmail.com # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell @@ -17,20 +17,20 @@ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # -# "made in Japan" +# "Made in Japan" #++ require 'thread' module Rufus module Lru - VERSION = '1.0.5' + VERSION = '1.0.7' # # A Hash that has a max size. After the maxsize has been reached, the # least recently used entries (LRU hence), will be discared to make # room for the new entries. @@ -46,40 +46,84 @@ # # h[:newer] = "b" # # puts h.inspect # >> {:newer=>"b", 3=>"aaa", 4=>"aaaa"} # + # One may want to squeeze hash manually + # + # h = LruHash.new(3, true) + # # or h.squeeze_on_demand=true after h is created + # . + # . + # h.squeeze! + # + # If a value has destructor method #clear it may be called upon the + # key-value removal + # + # h = LruHash.new(33, does_not_matter, true) + # # or h.clear_value_on_removal=true after h is created + # # Nota bene: this class is not thread-safe. If you need something thread-safe, # use Rufus::Lru::SynchronizedHash. # class Hash < ::Hash attr_reader :maxsize attr_reader :lru_keys + attr_accessor :on_removal + # Initializes a LruHash with a given maxsize. # - def initialize(maxsize) + # Options: + # + # * :auto_squeeze + # defaults to true + # * :on_removal + # accepts false, a symbol or a lambda. + # * False is the default, values are removed, nothing special happens. + # * A symbol can be used to point to a method like :clear or :destroy + # that has to be called on the value just removed + # * A lambda/proc can be set, it's thus called (and passed the removed + # value as argument) each time a removal occurs + # + def initialize(maxsize, opts={}) super() @maxsize = maxsize @lru_keys = [] + + @auto_squeeze = opts.has_key?(:auto_squeeze) ? opts[:auto_squeeze] : true + @on_removal = opts[:on_removal] end def maxsize=(i) @maxsize = i - remove_lru + squeeze! if @auto_squeeze i end + def auto_squeeze=(b) + + squeeze! if b + @auto_squeeze = b + end + + def auto_squeeze? + + @auto_squeeze + end + def clear @lru_keys.clear + self.each_value { |v| call_on_removal(v) } + super end # Returns the keys with the lru in front. # @@ -94,11 +138,11 @@ super end def []=(key, value) - remove_lru + remove_lru if @auto_squeeze touch(key) super end @@ -109,22 +153,28 @@ # not using 'super', but in order not guaranteed at all... end def delete(key) + value = super + call_on_removal(value) + @lru_keys.delete(key) - super + value end # Returns a regular Hash with the entries in this hash. # def to_h {}.merge!(self) end + # public alias to remove_lru + def squeeze!; remove_lru; end + protected # Puts the key on top of the lru 'stack'. # The bottom being the lru place. # @@ -141,18 +191,29 @@ while size >= @maxsize delete(@lru_keys.delete_at(0)) end end + + def call_on_removal(value) + + if ! @on_removal + # nothing to do + elsif @on_removal.is_a?(Symbol) + value.send(@on_removal) + else # must be a block + @on_removal.call(value) + end + end end # # A thread-safe version of the lru hash. # - class SynchronizedHash < Hash + class SynchronizedHash < Rufus::Lru::Hash - def initialize(maxsize) + def initialize(maxsize, opts={}) super @mutex = Mutex.new end @@ -160,9 +221,14 @@ @mutex.synchronize { super } end def []=(key, value) + + @mutex.synchronize { super } + end + + def squeeze! @mutex.synchronize { super } end end end