breadth first traversal

should fix referencing
This commit is contained in:
Torsten Ruger 2015-06-19 16:53:19 +03:00
parent 4754ba60be
commit ca803225c6
3 changed files with 56 additions and 43 deletions

View File

@ -16,74 +16,87 @@ module Sof
@root = root @root = root
@counter = 1 @counter = 1
@objects = {} @objects = {}
add(root , 0) add_object( root , 0)
collect_level(0 , [root])
end end
attr_reader :objects , :root attr_reader :objects , :root
private private
# recursively add reachable objects from this object # add object (as occurence) if it doesn't exist
# this is called from the initialize and is private # return object or nil
def add object , level def add_object object , level
# not storing simple (value) objects
return if is_value?(object)
# see if we we came accross this before # see if we we came accross this before
if( occurence = @objects[object.object_id] ) if( occurence = @objects[object.object_id] )
puts "reset level #{level} at #{occurence.level}" if occurence.referenced == 19 #puts "reset level #{level} at #{occurence.level}" if occurence.referenced #== 19
if occurence.level > level if occurence.level > level
#always store the most shallow level #always store the most shallow level
occurence.level = level occurence.level = level
end end
# and only one Occurence for each object, create a reference for the second occurence # and only one Occurence for each object, create a reference for the second occurence
unless occurence.referenced unless occurence.referenced
puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 14 puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 23
puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 19 # puts "referencing #{@counter} #{occurence.object.name}, at level #{level}/#{occurence.level} " if @counter == 19
occurence.set_reference(@counter) occurence.set_reference(@counter)
@counter = @counter + 1 @counter = @counter + 1
end end
return return nil
end end
# if first time see, create and store Occurence # if first time see, create and store Occurence
o = Occurence.new( object , level ) @objects[object.object_id] = Occurence.new( object , level )
@objects[object.object_id] = o return object
end
case object.class.name # recursively find reachable objects from this level of objects
when "Array" , "Parfait::List" # this is called from the initialize and is private
add_array object , level # we go through the tree in breadth first (which is a little more effort) to catch lowest
when "Hash" , "Parfait::Dictionary" # references.
add_hash object , level def collect_level level , objects
else next_level = Array.new
# and recursively add attributes #puts "collect level #{level} #{objects.length}"
attributes = attributes_for(object) objects.each do |object|
attributes.each do |a| #puts "collect level #{level} #{object.object_id}"
val = get_value( object , a) # not storing simple (value) objects
add(val , level + 1) next if is_value?(object)
end case object.class.name
#TODO get all superclsses here, but this covers 99% so . . moving on when "Array" , "Parfait::List"
superclasses = [object.class.superclass.name] collect_array object , next_level
if superclasses.include?( "Array") or superclasses.include?( "List") when "Hash" , "Parfait::Dictionary"
add_array object , level collect_hash object, next_level
end else
if superclasses.include?( "Hash") or superclasses.include?( "Dictionary") # and recursively add attributes
add_hash object , level attributes = attributes_for(object)
attributes.each do |a|
val = get_value( object , a)
next_level << val
end
#TODO get all superclsses here, but this covers 99% so . . moving on
superclasses = [object.class.superclass.name]
if superclasses.include?( "Array") or superclasses.include?( "List")
collect_array object, next_level
end
if superclasses.include?( "Hash") or superclasses.include?( "Dictionary")
collect_hash object, next_level
end
end end
end end
new_objects = next_level.collect { |o| add_object(o , level + 1) }
new_objects.compact!
# recurse , but break off if hit bottom
collect_level( level + 1 , new_objects) unless new_objects.empty?
end end
# and hash keys/values # and hash keys/values
def add_hash hash ,level def collect_hash hash , next_level
hash.each do |a,b| hash.each do |a,b|
add(a , level + 1) next_level << a
add(b , level + 1) next_level << b
end end
end end
# and array values # and array values
def add_array array , level def collect_array array , next_level
array.each do |a| array.each do |a|
add(a , level + 1) next_level << a
end end
end end
end end
# TODO, since this class only has one function, and one instance
# it could be merged as class functions to Occurence
end end

View File

@ -9,8 +9,8 @@ module Sof
class SimpleNode < Node class SimpleNode < Node
# data is a string that is written out in "out" function # data is a string that is written out in "out" function
def initialize data , ref = nil def initialize data
super(ref) super(nil) # simple nodes can not be referenced, always value
@data = data @data = data
end end

View File

@ -36,7 +36,7 @@ class TestRefs < MiniTest::Test
object2 = ObjectWithAttributes.new object2 = ObjectWithAttributes.new
object.extra = [object2] object.extra = [object2]
@out = [ {:one => object} , object2 ] @out = [ {:one => object} , object2 ]
check "- - :one => ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [->1])\n- &1 ObjectWithAttributes(:name => 'some name', :number => 1234)" check "- - :one => ObjectWithAttributes(:name => 'some name', :number => 1234, :extra => [->2])\n- &2 ObjectWithAttributes(:name => 'some name', :number => 1234)"
end end
end end