“Tanaka Akira” akr@m17n.org wrote in message
news:87znjnvl2e.fsf@serein.a02.aist.go.jp…
In article 200307091409.h69E9Qn21340@moulon.inra.fr,
ts decoux@moulon.inra.fr writes:
I must say that I’ve not understood
svg% cat b.rb
This works well because an object is allocated before child object is
loaded as:
obj = self.new
@@loaded.push(obj)
obj.ref = Marshal.load(str).shift
But marshal.c cannot know an object allocated by C._load before
calling C._load.
if I run Guys example through a fairly well tested (- the thread part;-)
“Compare by Value” module
···
module CompareByValue
def ==(other)
if not instance_of?(other.class)
false
elsif equal?(other)
true
elsif id < other.id
CompareByValue.comp?(self,other)
else
CompareByValue.comp?(other,self)
end
end
end
class << CompareByValue
Seen is a book keeping class for currently
active thread local CompareByValue comparisons.
class Seen < Hash
# Helper class to store Id Pairs.
const_set :Pair, Struct.new(:l,:r)
def initialize(l,r)
store(Pair.new(l,r),true)
end
def default(key)
store(key,true)
nil
end
def seen?(l,r)
self[Pair.new(l,r)]
end
def unseen(l,r)
delete(Pair.new(l,r))
end
end
symbol mangling
const_set :SEEN_COMPS, “CBV#{id}_comps”.intern
const_set :NUM_CALLS, “CBV#{id}_calls”.intern
def comp?(l,r)
return true if thread_local_seen?(l,r)
begin
Thread.current[NUM_CALLS] +=1
return Comp.new.comp?(l,r)
rescue
Thread.current[SEEN_COMPS].unseen(l,r)
raise
ensure
if (Thread.current[NUM_CALLS] -= 1).zero?
Thread.current[SEEN_COMPS].clear
end
end
end
def thread_local_seen?(l,r)
if comps = Thread.current[SEEN_COMPS]
comps.seen?(l,r)
else
Thread.current[NUM_CALLS] = 0
Thread.current[SEEN_COMPS] = Seen.new(l,r)
false
end
end
class Comp < Hash
def comp?(l,r)
return true if l.equal?(r)
vars = l.instance_variables.sort!
return false unless vars == r.instance_variables.sort!
#
store(l.id,r.id)
vars.each { |name|
ll = l.instance_eval(name)
rr = r.instance_eval(name)
if CompareByValue === ll
return false unless ll.instance_of?(rr.class)
if rr_seen_id = self[ll.id]
return false unless rr_seen_id == rr.id
else
return false unless comp?(ll,rr)
end
else
return false unless ll == rr
end
}
return true
end
end
end
class C
include CompareByValue
attr_accessor :ref
@@dumped = {}
@@loaded =
@@num = 0
def _dump(limit)
if @@dumped[self]
“\000#{@@dumped[self]}\000”
else
@@dumped[self] = @@num
@@num += 1
Marshal.dump([@ref], limit-1)
end
end
def self._load(str)
if /\A\000(\d+)\000\z/ =~ str
obj = @@loaded[$1.to_i]
else
obj = self.new
@@loaded.push(obj)
obj.ref = Marshal.load(str).shift
end
obj
end
end
Kernel.const_set :A, C.new
Kernel.const_set :B, C.new
A.instance_eval { @ref = B; @xxx = 1 }
B.instance_eval { @ref = A; @xxx = 2 }
p A
p B
p a = Marshal.load(Marshal.dump(A))
p b = Marshal.load(Marshal.dump(B))
p B == A # false
p b == a # true
p B == a # false
p b == a.ref # true
p B == A.ref # true
p B == a.ref # false
p b == A.ref # false
I am getting an output that does not look quite right to me
#<C:0x2788020 @ref=#<C:0x2787918 @ref=#<C:0x2788020 …>, @xxx=2>, @xxx=1>
#<C:0x2787918 @ref=#<C:0x2788020 @ref=#<C:0x2787918 …>, @xxx=1>, @xxx=2>
#<C:0x2786d30 @ref=#<C:0x2786928 @ref=#<C:0x2786d30 …>>>
#<C:0x2786928 @ref=#<C:0x2786d30 @ref=#<C:0x2786928 …>>>
false
true
false
true
true
false
false
but I am not sure if I would blame this on the current “_dump, _load”
scheme.
/Christoph