lib/pycall/wrapper_object_cache.rb in pycall-1.3.1 vs lib/pycall/wrapper_object_cache.rb in pycall-1.4.0

- old
+ new

@@ -1,18 +1,60 @@ module PyCall class WrapperObjectCache + + begin + ObjectSpace::WeakMap.new[42] = Object.new + rescue + WMAP_SUPPORT_INT_KEY = false + else + WMAP_SUPPORT_INT_KEY = true + end + + if WMAP_SUPPORT_INT_KEY + def self.get_key(pyptr) + pyptr.__address__ + end + else + class Key + @address_key_map = {} + + def self.[](address) + # An instance of Key created here is parmanently cached in @address_key_map. + # This behavior is intentional. + @address_key_map[address] ||= new(address) + end + + def initialize(address) + @address = address + end + + attr_reader :address + + def ==(other) + case other + when Key + self.address == other.address + else + super + end + end + end + + def self.get_key(pyptr) + Key[pyptr.__address__] + end + end + def initialize(*restricted_pytypes) unless restricted_pytypes.empty? restricted_pytypes.each do |pytype| next if pytype.kind_of? PyTypePtr raise TypeError, "unexpected type of object in the arguments (#{pytype.class} for PyCall::PyTypePtr)" end end @restricted_pytypes = restricted_pytypes - @wrapper_object_table = {} - @wrapped_pyptr_table = {} - @weakref_table = {} + @wrapper_object_table = ObjectSpace::WeakMap.new end def lookup(pyptr) # TODO: check pytypeptr type unless pyptr.kind_of? PyPtr @@ -23,39 +65,23 @@ unless @restricted_pytypes.any? {|pytype| pyptr.kind_of? pytype } raise TypeError, "unexpected argument Python type #{pyptr.__ob_type__.__name__} (expected either of them in [#{@restricted_pytypes.map(&:__tp_name__).join(', ')}])" end end - wrapper_object_id = @wrapper_object_table[pyptr.__address__] - if wrapper_object_id - wrapper_object = ObjectSpace._id2ref(wrapper_object_id) rescue nil - return wrapper_object if wrapper_object + key = self.class.get_key(pyptr) + wrapper_object = @wrapper_object_table[key] + unless wrapper_object + wrapper_object = yield(pyptr) + check_wrapper_object(wrapper_object) + @wrapper_object_table[key] = wrapper_object end - wrapper_object = yield(pyptr) - check_wrapper_object(wrapper_object) - register_wrapper_object(pyptr, wrapper_object) - wrapper_object end def check_wrapper_object(wrapper_object) unless wrapper_object.kind_of?(PyObjectWrapper) raise TypeError, "unexpected wrapper object (expected an object extended by PyObjectWrapper)" end - end - - def register_wrapper_object(pyptr, wrapper_object) - @wrapper_object_table[pyptr.__address__] = wrapper_object.__id__ - @wrapped_pyptr_table[wrapper_object.__id__] = pyptr.__address__ - ObjectSpace.define_finalizer(wrapper_object, &method(:unregister_wrapper_object)) - # TODO: weakref - self - end - - def unregister_wrapper_object(wrapper_object_id) - pyptr_addr = @wrapped_pyptr_table.delete(wrapper_object_id) - @wrapper_object_table.delete(pyptr_addr) if pyptr_addr - self end end end