0
0
Fork 0

added a binary tree storage

This commit is contained in:
Gibheer 2011-06-16 13:18:43 +02:00
parent 61b962fea3
commit 1d2035c637
7 changed files with 273 additions and 0 deletions

View File

@ -0,0 +1,136 @@
module Polecat
module Storage
# This class is a storage engine based on a simple hash.
class BinaryStorage < Storage
def initialize
@root = nil
end
# add a new key value pair
def add key, value = nil
if key.class == Node
new_node = key
else
check_key key
new_node = Node.new key, value
end
if @root.nil?
@root = new_node
else
cur_node = @root
while cur_node.lower != new_node && cur_node.upper != new_node
if cur_node.key > new_node.key
if cur_node.lower.nil?
cur_node.lower = new_node
else
cur_node = cur_node.lower
end
elsif cur_node.key <= new_node.key
if cur_node.upper.nil?
cur_node.upper = new_node
else
cur_node = cur_node.upper
end
end
end # end of while
end
end
def delete key
check_key key
cur_node = @root
parent = nil
while !cur_node.nil?
if cur_node.key == key
if parent.nil?
@root = nil
else
if parent.lower == cur_node
parent.lower = nil
else
parent.upper = nil
end
end
add cur_node.lower unless cur_node.lower.nil?
add cur_node.upper unless cur_node.upper.nil?
return cur_node.value
else
if cur_node.key < key
parent = cur_node
cur_node = cur_node.upper
else
parent = cur_node
cur_node = cur_node.lower
end
end
end
nil
end
def interval lower, upper, node = @root
check_key lower
check_key upper
select do |key|
lower <= key && key <= upper
end
end
def find key
check_key key
cur_node = @root
until cur_node.nil?
if cur_node.key == key
return cur_node.value
elsif
if cur_node.key > key
cur_node = cur_node.lower
else
cur_node = cur_node.upper
end
end
end
nil
end
def select node = @root, &block
if node.nil?
[]
else
rs = []
rs << node.value if block.call(node.key)
rs += (select node.lower, &block)
rs += (select node.upper, &block)
end
end
def count node = @root
if node.nil?
0
else
1 + (count node.lower) + (count node.upper)
end
end
def check_key key
unless key.respond_to?(:<=>) && key.respond_to?(:<=)
raise ArgumentError, 'key does not support #<=>'
end
end
private :check_key
class Node
attr_accessor :value, :lower, :upper
attr_reader :key
def initialize key, value
@key = key
@value = value
end
end
end
end
end

View File

@ -0,0 +1,22 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/binary_storage'
describe "BinaryStorage#add" do
let (:s) { Polecat::Storage::BinaryStorage.new }
it "raises the element count" do
s.add('foo', 'bar')
s.count.should == 1
end
it "raises the element count with every add" do
s.add('foo', 1)
s.add('bar', 2)
s.add('baz', 3)
s.count.should == 3
end
it "raises an error when the attribute does not support #<=>" do
lambda { s.add(nil, 'baz') }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,28 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/binary_storage'
describe "BinaryStorage#delete" do
let (:s) { Polecat::Storage::BinaryStorage.new }
before do
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foo'
end
it "decrements the element count" do
s.delete('foo')
s.count.should == 2
end
it "returns the value of the deleted key" do
s.delete('foo').should == 'bar'
end
it "returns nil when the element was not found" do
s.delete('foobar').should be(nil)
end
it "raises an error when the argument does not support #<=>" do
lambda { s.delete(:foo) }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,24 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/binary_storage'
describe "BinaryStorage#find" do
let (:s) { Polecat::Storage::BinaryStorage.new }
before do
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foobar'
s.add 'zum', 'zum'
end
it "returns nil when the element was not found" do
s.find('baba').should be(nil)
end
it "returns the value of the key" do
s.find('foo').should == 'bar'
end
it "raises an error when the type does not know #<=>" do
lambda { s.find(:foo) }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,28 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/binary_storage'
describe "BinaryStorage#interval" do
let (:s) { Polecat::Storage::BinaryStorage.new }
before do
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foobar'
s.add 'zum', 'zum'
end
it "returns an empty array when no element was found" do
s.interval('a', 'b').should == []
end
it "returns an array of found elements" do
s.interval('ba', 'bb').sort.should == ['baz', 'foobar']
end
it "includes the search values" do
s.interval('bar', 'baz').sort.should == ['baz', 'foobar']
end
it "raises an error when one of the arguments does not implement #<=>" do
lambda { s.interval(1, :foo) }.should raise_error(ArgumentError)
end
end

View File

@ -0,0 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/binary_storage'
describe "BinaryStorage#new" do
it "creates a new storage object" do
s = Polecat::Storage::BinaryStorage.new
s.kind_of?(Polecat::Storage::Storage).should == true
s.class.should be(Polecat::Storage::BinaryStorage)
end
end

View File

@ -0,0 +1,25 @@
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require 'polecat/storage/binary_storage'
describe "BinaryStorage#select" do
let (:s) { Polecat::Storage::BinaryStorage.new }
before do
s.add 'key', 'value'
s.add 'foo', 'bar'
s.add 'bar', 'baz'
s.add 'baz', 'foobar'
end
it "returns an empty array, when no element was selected" do
(s.select {|element| false }).should == []
end
it "takes a block as an argument" do
(s.select {|element| element.match /ba*/ }).sort.should == ['baz', 'foobar']
end
it "does not handle errors" do
lambda { s.select {|element| raise ArgumentError }}.should(
raise_error(ArgumentError))
end
end