Skip to content

Commit

Permalink
Refactoring and broke interval_skip_list.rb out into multiple files i…
Browse files Browse the repository at this point in the history
…n a directory
  • Loading branch information
nathansobo committed Jan 25, 2008
1 parent 79e8d53 commit d83a9c5
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 322 deletions.
326 changes: 4 additions & 322 deletions lib/treetop/runtime/interval_skip_list.rb
Original file line number Diff line number Diff line change
@@ -1,322 +1,4 @@
class IntervalSkipList
def initialize
@head = HeadNode.new(max_height)
@ranges = {}
end

def max_height
3
end

def empty?
head.forward[0].nil?
end

def containing(n)
containing = []
cur_node = head
(max_height - 1).downto(0) do |cur_level|
while (next_node = cur_node.forward[cur_level]) && next_node.key <= n
cur_node = next_node
if cur_node.key == n
return containing + (cur_node.markers - cur_node.endpoint_of)
end
end
containing.concat(cur_node.forward_markers[cur_level])
end
containing
end

def insert(range, marker)
ranges[marker] = range
first_node = insert_node(range.first)
first_node.endpoint_of.push(marker)
last_node = insert_node(range.last)
last_node.endpoint_of.push(marker)

cur_node = first_node
cur_level = first_node.height - 1
while next_node_at_level_inside_range?(cur_node, cur_level, range)
while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
cur_level += 1
end
cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
end

while node_inside_range?(cur_node, range)
while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
cur_level -= 1
end
cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
end
end

def delete(marker)
range = ranges[marker]
path_to_first_node = make_path
first_node = find(range.first, path_to_first_node)

cur_node = first_node
cur_level = first_node.height - 1
while next_node_at_level_inside_range?(cur_node, cur_level, range)
while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
cur_level += 1
end
cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
end

while node_inside_range?(cur_node, range)
while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
cur_level -= 1
end
cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
end
last_node = cur_node

first_node.endpoint_of.delete(marker)
if first_node.endpoint_of.empty?
first_node.delete(path_to_first_node)
end

last_node.endpoint_of.delete(marker)
if last_node.endpoint_of.empty?
path_to_last_node = make_path
find(range.last, path_to_last_node)
last_node.delete(path_to_last_node)
end
end

protected
attr_reader :head, :ranges

def insert_node(key)
path = make_path
found_node = find(key, path)
if found_node && found_node.key == key
return found_node
else
return Node.new(key, next_node_height, path)
end
end

def delete_node(key)
path = make_path
found_node = find(key, path)
found_node.delete(path) if found_node.key == key
end

def find(key, path)
cur_node = head
(max_height - 1).downto(0) do |cur_level|
while (next_node = cur_node.forward[cur_level]) && next_node.key < key
cur_node = next_node
end
path[cur_level] = cur_node
end
cur_node.forward[0]
end

def make_path
Array.new(max_height, nil)
end

def next_node_height
nil
end

def can_ascend_from?(node, level)
level < node.height - 1
end

def can_descend_from?(level)
level > 0
end

def node_inside_range?(node, range)
node.key < range.last
end

def next_node_at_level_inside_range?(node, level, range)
node.forward[level] && node.forward[level].key <= range.last
end

def next_node_at_level_outside_range?(node, level, range)
(node.forward[level].nil? || node.forward[level].key > range.last)
end

def mark_forward_path_at_level(node, level, marker)
node.forward_markers[level].push(marker)
next_node = node.forward[level]
next_node.markers.push(marker)
node = next_node
end

def unmark_forward_path_at_level(node, level, marker)
node.forward_markers[level].delete(marker)
next_node = node.forward[level]
next_node.markers.delete(marker)
node = next_node
end

def nodes
nodes = []
cur_node = head.forward[0]
until cur_node.nil?
nodes << cur_node
cur_node = cur_node.forward[0]
end
nodes
end

class HeadNode
attr_reader :height, :forward, :forward_markers

def initialize(height)
@height = height
@forward = Array.new(height, nil)
@forward_markers = Array.new(height) {|i| []}
end
end

class Node < HeadNode
attr_reader :key, :markers, :endpoint_of

def initialize(key, height, path)
super(height)
@key = key
@markers = []
@endpoint_of = []
update_forward_pointers(path)
promote_markers(path)
end

def delete(path)
0.upto(height - 1) do |i|
path[i].forward[i] = forward[i]
end
demote_markers(path)
end

protected

def update_forward_pointers(path)
0.upto(height - 1) do |i|
forward[i] = path[i].forward[i]
path[i].forward[i] = self
end
end

def promote_markers(path)
promoted = []
new_promoted = []
0.upto(height - 1) do |i|
incoming_markers = path[i].forward_markers[i]
markers.concat(incoming_markers)

incoming_markers.each do |marker|
if can_be_promoted_higher?(marker, i)
new_promoted.push(marker)
forward[i].delete_marker_from_path(marker, i, forward[i+1])
else
forward_markers[i].push(marker)
end
end

promoted.each do |marker|
if can_be_promoted_higher?(marker, i)
new_promoted.push(marker)
forward[i].delete_marker_from_path(marker, i, forward[i+1])
else
forward_markers[i].push(marker)
end
end

promoted = new_promoted
new_promoted = []
end
end

def demote_markers(path)
demoted = []
new_demoted = []

(height - 1).downto(0) do |i|
incoming_markers = path[i].forward_markers[i].dup
incoming_markers.each do |marker|
unless node_in_range_reachable_from_level?(marker, i)
path[i].forward_markers[i].delete(marker)
new_demoted.push(marker)
end
end

demoted.each do |marker|
path[i+1].place_marker_on_inbound_path(marker, i, path[i])

if forward[i].markers.include?(marker)
path[i].forward_markers[i].push(marker)
else
new_demoted.push(marker)
end
end

demoted = new_demoted
new_demoted = []
end

demoted = []
new_demoted = []

(height - 1).downto(0) do |i|
forward_markers[i].each do |marker|
new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker)
end

demoted.each do |marker|
forward[i].place_marker_on_outbound_path(marker, i, forward[i + 1])
new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker)
end

demoted = new_demoted
new_demoted = []
end
end

def node_in_range_reachable_from_level?(marker, level)
level.upto(height - 1) do |i|
return true if forward[i].markers.include?(marker)
end
false
end

def can_be_promoted_higher?(marker, level)
level < height - 1 && forward[level + 1] && forward[level + 1].markers.include?(marker)
end

def delete_marker_from_path(marker, level, terminus)
cur_node = self
until cur_node == terminus
cur_node.forward_markers[level].delete(marker)
cur_node.markers.delete(marker)
cur_node = cur_node.forward[level]
end
end

def place_marker_on_outbound_path(marker, level, terminus)
cur_node = self
until cur_node == terminus
cur_node.forward_markers[level].push(marker)
cur_node.markers.push(marker)
cur_node = cur_node.forward[level]
end
end

def place_marker_on_inbound_path(marker, level, terminus)
cur_node = self
until cur_node == terminus
cur_node.forward_markers[level].push(marker)
cur_node = cur_node.forward[level]
cur_node.markers.push(marker)
end
end
end
end
dir = File.dirname(__FILE__)
require "#{dir}/interval_skip_list/interval_skip_list.rb"
require "#{dir}/interval_skip_list/head_node.rb"
require "#{dir}/interval_skip_list/node.rb"
15 changes: 15 additions & 0 deletions lib/treetop/runtime/interval_skip_list/head_node.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class IntervalSkipList
class HeadNode
attr_reader :height, :forward, :forward_markers

def initialize(height)
@height = height
@forward = Array.new(height, nil)
@forward_markers = Array.new(height) {|i| []}
end

def top_level
height - 1
end
end
end
Loading

0 comments on commit d83a9c5

Please sign in to comment.