add simple_test and enumerable range/dup queries. improve absolute sort
This commit is contained in:
parent
5592d5b746
commit
af7cb910ac
|
@ -1,4 +1,4 @@
|
||||||
require 'bdb'
|
require 'bdb' if not defined?(Bdb)
|
||||||
|
|
||||||
class Bdb::Simple
|
class Bdb::Simple
|
||||||
include Enumerable
|
include Enumerable
|
||||||
|
@ -19,7 +19,7 @@ class Bdb::Simple
|
||||||
@db = Bdb::Db.new
|
@db = Bdb::Db.new
|
||||||
@db.flags = Bdb::DB_DUPSORT if dup?
|
@db.flags = Bdb::DB_DUPSORT if dup?
|
||||||
@db.btree_compare = lambda do |db, key1, key2|
|
@db.btree_compare = lambda do |db, key1, key2|
|
||||||
compare_absolute(Marshal.load(key1), Marshal.load(key2))
|
self.class.compare_absolute(Marshal.load(key1), Marshal.load(key2))
|
||||||
end
|
end
|
||||||
@db.open(nil, file, nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
@db.open(nil, file, nil, Bdb::Db::BTREE, Bdb::DB_CREATE, 0)
|
||||||
end
|
end
|
||||||
|
@ -30,35 +30,18 @@ class Bdb::Simple
|
||||||
db[Marshal.dump(key)] = Marshal.dump(value)
|
db[Marshal.dump(key)] = Marshal.dump(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def delete(key)
|
||||||
|
db.del(nil, Marshal.dump(key), 0)
|
||||||
|
end
|
||||||
|
|
||||||
def [](key)
|
def [](key)
|
||||||
if key.kind_of?(Range)
|
if key.kind_of?(Range) or dup?
|
||||||
values = []
|
Bdb::SimpleSet.new(db, key)
|
||||||
cursor = db.cursor(nil, 0)
|
|
||||||
k,v = cursor.get(Marshal.dump(key.first), nil, Bdb::DB_SET_RANGE)
|
|
||||||
while k and key.include?(Marshal.load(k))
|
|
||||||
values << Marshal.load(v)
|
|
||||||
k, v = cursor.get(nil, nil, Bdb::DB_NEXT)
|
|
||||||
end
|
|
||||||
cursor.close
|
|
||||||
values
|
|
||||||
else
|
else
|
||||||
key = Marshal.dump(key)
|
v = db.get(nil, Marshal.dump(key), nil, 0)
|
||||||
if dup?
|
|
||||||
values = []
|
|
||||||
cursor = db.cursor(nil, 0)
|
|
||||||
k,v = cursor.get(key, nil, Bdb::DB_SET)
|
|
||||||
while data
|
|
||||||
values << Marshal.load(v)
|
|
||||||
k,v = cursor.get(nil, nil, Bdb::DB_NEXT_DUP)
|
|
||||||
end
|
|
||||||
cursor.close
|
|
||||||
values
|
|
||||||
else
|
|
||||||
v = db.get(nil, key, nil, 0)
|
|
||||||
Marshal.load(v) if v
|
Marshal.load(v) if v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def each
|
def each
|
||||||
cursor = db.cursor(nil, 0)
|
cursor = db.cursor(nil, 0)
|
||||||
|
@ -86,20 +69,66 @@ class Bdb::Simple
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.compare_absolute(left, right)
|
def self.compare_absolute(left, right)
|
||||||
|
if left.class == right.class
|
||||||
if left.is_a?(Array) and right.is_a?(Array)
|
if left.is_a?(Array) and right.is_a?(Array)
|
||||||
|
# Arrays: compare one element at a time.
|
||||||
left.zip(right) do |l,r|
|
left.zip(right) do |l,r|
|
||||||
comp = compare_absolute(l, r)
|
comp = compare_absolute(l, r)
|
||||||
return comp unless comp == 0
|
return comp unless comp == 0
|
||||||
end
|
end
|
||||||
left.size == right.size ? 0 : -1
|
left.size == right.size ? 0 : -1
|
||||||
elsif left.kind_of?(right.class) or right.kind_of?(left.class)
|
elsif left.is_a?(Hash) and right.is_a?(Hash)
|
||||||
left <=> right rescue 0
|
# Hashes: sort the keys and compare as an array of arrays.
|
||||||
elsif left.is_a?(NilClass)
|
left = left.to_a.sort {|a,b| compare_absolute(a[0],b[0])}
|
||||||
-1
|
right = right.to_a.sort {|a,b| compare_absolute(a[0],b[0])}
|
||||||
elsif right.is_a?(NilClass)
|
compare_absolute(left, right)
|
||||||
1
|
|
||||||
else
|
else
|
||||||
|
begin
|
||||||
|
# Try to use the spaceship operator.
|
||||||
|
left <=> right
|
||||||
|
rescue NoMethodError => e
|
||||||
|
left.hash <=> right.hash
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Nil is the smallest. Hash is the largest. All other objects are sorted by class name.
|
||||||
|
return -1 if left.is_a?(NilClass)
|
||||||
|
return 1 if right.is_a?(NilClass)
|
||||||
|
return 1 if left.is_a?(Hash)
|
||||||
|
return -1 if right.is_a?(Hash)
|
||||||
|
|
||||||
|
# Compare class names and hashes as a last resort if that fails.
|
||||||
right.class.name <=> left.class.name
|
right.class.name <=> left.class.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class Bdb::SimpleSet
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
def initialize(db, key)
|
||||||
|
@db = db
|
||||||
|
@key = key
|
||||||
|
end
|
||||||
|
attr_reader :db, :key
|
||||||
|
|
||||||
|
def each
|
||||||
|
if key.kind_of?(Range)
|
||||||
|
cursor = db.cursor(nil, 0)
|
||||||
|
k,v = cursor.get(Marshal.dump(key.first), nil, Bdb::DB_SET_RANGE)
|
||||||
|
while k and key.include?(Marshal.load(k))
|
||||||
|
yield Marshal.load(v)
|
||||||
|
k, v = cursor.get(nil, nil, Bdb::DB_NEXT)
|
||||||
|
end
|
||||||
|
cursor.close
|
||||||
|
else
|
||||||
|
cursor = db.cursor(nil, 0)
|
||||||
|
k,v = cursor.get(Marshal.dump(key), nil, Bdb::DB_SET)
|
||||||
|
while k
|
||||||
|
yield Marshal.load(v)
|
||||||
|
k,v = cursor.get(nil, nil, Bdb::DB_NEXT_DUP)
|
||||||
|
end
|
||||||
|
cursor.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in a new issue