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