EfficientFIFO

toying-with-ramdb
Philippe PITTOLI 2024-05-26 04:02:11 +02:00
parent 981cdc92b8
commit 313374d58e
4 changed files with 97 additions and 1 deletions

View File

@ -17,3 +17,20 @@ describe "FIFO" do
fifo.data.should eq([5, 4] of Int32) fifo.data.should eq([5, 4] of Int32)
end end
end end
describe "EfficientFIFO" do
it "add and remove values" do
fifo = EfficientFIFO(Int32).new 3 # Only 3 allowed entries.
(fifo << 1).should be_nil # there is still room in the fifo
(fifo << 2).should be_nil # there is still room in the fifo
(fifo << 3).should be_nil # last entry without exceeding the allowed size
(fifo << 4).should eq 1 # -> 1 (least recently used data)
(fifo << 4).should be_nil # -> nil (already in the fifo)
(fifo << 2).should be_nil # -> nil (already in the fifo)
(fifo << 5).should eq 3 # -> 3 (least recently used data)
fifo.list.to_s.should eq "[ 5, 2, 4 ]"
fifo.delete 2
fifo.list.to_s.should eq "[ 5, 4 ]"
end
end

View File

@ -94,6 +94,19 @@ describe "DoubleLinkedList" do
list.shift.value.should eq 4 list.shift.value.should eq 4
end end
it "unshift" do
list = DoubleLinkedList(Int32).new
list.unshift 1
list.unshift 2
list.unshift 3
list.unshift 4
list.pop
node = list.unshift 4
list.to_s.should eq "[ 4, 4, 3, 2 ]"
list.delete node
list.to_s.should eq "[ 4, 3, 2 ]"
end
it "peek" do it "peek" do
list = DoubleLinkedList(Int32).new list = DoubleLinkedList(Int32).new
list << 1 << 2 << 3 << 4 list << 1 << 2 << 3 << 4

View File

@ -1,3 +1,5 @@
require "./list.cr"
# This class enables to keep track of used data. # This class enables to keep track of used data.
# #
# Each time a value is added, it is put in a FIFO structure. # Each time a value is added, it is put in a FIFO structure.
@ -46,6 +48,40 @@ end
# TODO: this is a draft. # TODO: this is a draft.
class EfficientFIFO(V) class EfficientFIFO(V)
# This array is used as the *fifo structure*.
property list : DoubleLinkedList(V)
property hash : Hash(V, DoubleLinkedList::Node(V))
def initialize(@max_entries : UInt32) def initialize(@max_entries : UInt32)
@list = DoubleLinkedList(V).new
@hash = Hash(V, DoubleLinkedList::Node(V)).new
end
# Pushes a value in the FIFO and gets the oldest value whether it exceeds the allowed number of entries.
# NOTE: `#<<(v : V)` is (almost) the only function since it's enough for the intended use, feel free to improve this.
def <<(v : V) : V?
if node = hash[v]?
list.delete node
end
# push as the first value of the structure
node = @list.unshift v
hash[v] = node
# remove least recently used entry if `@list` is too big
if list.size > @max_entries
node = @list.pop
hash.delete node.value
node.value
else
nil
end
end
# Removes a value.
def delete(v : V)
if node = hash[v]?
list.delete node
end
end end
end end

View File

@ -88,7 +88,37 @@ class DoubleLinkedList(V)
new_node new_node
end end
# Removes an entry.
#
# ```
# list = DoubleLinkedList(Int32).new
# list << 1 << 2 << 3 << 4 # -> [ 1, 2, 3, 4 ]
# list.delete_at 2 # -> [ 1, 2, 4 ]
# ```
def delete(n : Node(V)) : Node(V)
if n == @first
@first = n.next
end
if n == @last
@last = n.previous
end
if prev_node = n.previous
prev_node.next = n.next
end
if next_node = n.next
next_node.previous = n.previous
end
@size -= 1
n
end
# Removes an entry at an index. # Removes an entry at an index.
#
# ```
# list = DoubleLinkedList(Int32).new
# list << 1 << 2 << 3 << 4 # -> [ 1, 2, 3, 4 ]
# list.delete_at 2 # -> [ 1, 2, 4 ]
# ```
def delete_at(index : Int32) : Node(V) def delete_at(index : Int32) : Node(V)
if index == 0 if index == 0
shift shift
@ -204,7 +234,7 @@ class DoubleLinkedList(V)
@size += 1 @size += 1
new_node new_node
else else
push(value) push value
end end
end end