M spec/sparse/vector_spec.cr => spec/sparse/vector_spec.cr +82 -0
@@ 91,4 91,86 @@ describe Sparse::Vector do
v.extract_element(43).should be_nil
end
end
+
+ describe "#set_element" do
+ it "inserts at the provided index" do
+ context "populated" do
+ v = Sparse::Vector(Int32, 10000).random 1000
+ v.set_element 42, 1729
+ v.extract_element(42).should eq(1729)
+ end
+
+ context "empty" do
+ v = Sparse::Vector(Int32, 10000).new
+ v.set_element 42, 1729
+ v.extract_element(42).should eq(1729)
+ end
+ end
+
+ it "overwrites an existing value if present" do
+ v = Sparse::Vector(Int32, 10000).new
+ v.set_element 42, 1729
+ v.set_element 42, 1
+ v.extract_element(42).should eq(1)
+ end
+
+ it "raises when out of bounds" do
+ v = Sparse::Vector(Int32, 100).new
+ expect_raises(IndexError) do
+ v.set_element 1000, 42
+ end
+ end
+ end
+
+ describe "#remove_element" do
+ it "drops the element at the specified index" do
+ v = Sparse::Vector(Int32, 100).new
+ v.set_element 42, 1729
+ v.remove_element(42).should eq(1729)
+ v.extract_element(0).should be_nil
+ end
+
+ it "ignore unset element indicies" do
+ v = Sparse::Vector(Int32, 100).new
+ v.remove_element(42).should be_nil
+ end
+
+ it "raises when out of bounds" do
+ v = Sparse::Vector(Int32, 100).new
+ expect_raises(IndexError) do
+ v.remove_element 1000
+ end
+ end
+ end
+
+ describe "#extract_element" do
+ it "returns to the element at the specified index" do
+ v = Sparse::Vector(Int32, 100).new
+ v.set_element 42, 1729
+ v.extract_element(42).should eq(1729)
+ end
+
+ it "returns nil if the element does not exist" do
+ v = Sparse::Vector(Int32, 100).new
+ v.extract_element(42).should be_nil
+ end
+
+ it "raises when out of bounds" do
+ v = Sparse::Vector(Int32, 100).new
+ expect_raises(IndexError) do
+ v.extract_element 1000
+ end
+ end
+ end
+
+ describe "#extract_tuples" do
+ it "provides the underlying idx, val arrays" do
+ idx = Sparse::Spec::Random.rand(Array(UInt64), 1000, max: 10000, sorted: true)
+ val = Sparse::Spec::Random.rand(Array(UInt8), 1000)
+ vec = Sparse::Vector(UInt8, 10000).new idx, val
+ idx2, val2 = vec.extract_tuples
+ idx2.should be(idx)
+ val2.should be(val)
+ end
+ end
end
M spec/spec_helper.cr => spec/spec_helper.cr +13 -3
@@ 11,6 11,17 @@ module Sparse::Spec::Random
SOURCE.rand type
end
+ def self.rand(max)
+ SOURCE.rand max
+ end
+
+ # OPTIMIZE: build in O(n) when specs get slow. This is simple for now.
+ def self.rand(klass : Array(T).class, size, max = T::MAX, sorted = false) : Array(T) forall T
+ arr = Array.new(size) { rand T.new(max) }
+ arr.sort! if sorted
+ arr
+ end
+
::Spec.before_suite do
puts "Running with random seed: #{SEED}"
end
@@ 18,9 29,8 @@ end
struct Sparse::Vector(T, N)
def self.random(nvals = 1000)
- # OPTIMIZE: build in O(n) specs get slow. This is simple for now.
- idx = Array.new(nvals) { Sparse::Spec::Random.rand UInt64 }.sort!
- val = Array.new(nvals) { Sparse::Spec::Random.rand T }
+ idx = Spec::Random.rand(Array(UInt64), nvals, max: N, sorted: true)
+ val = Spec::Random.rand(Array(T), nvals)
new idx, val
end
end
M src/sparse/vector.cr => src/sparse/vector.cr +2 -2
@@ 113,9 113,9 @@ module Sparse
end
# Extract one element of *self* into a scalar.
- @[AlwaysInline]
def extract_element(index : Int) : T?
- fetch(index) { nil }
+ check_index_out_of_bounds index
+ unsafe_fetch index
end
# Extract all elements with values assigned.