Skip to content

Commit

Permalink
Use specialized pointer_linked_list instead of static_list
Browse files Browse the repository at this point in the history
  • Loading branch information
bcardiff committed Nov 11, 2019
1 parent b540ce5 commit 3dd97bf
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 307 deletions.
206 changes: 0 additions & 206 deletions spec/std/crystal/static_list_spec.cr

This file was deleted.

26 changes: 11 additions & 15 deletions src/channel.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require "fiber"
require "crystal/spin_lock"
require "crystal/static_list"
require "crystal/pointer_linked_list"

# A `Channel` enables concurrent communication between fibers.
#
Expand Down Expand Up @@ -104,7 +104,8 @@ class Channel(T)

# :nodoc:
struct Sender(T)
include Crystal::StaticList::Node(self)
include Crystal::PointerLinkedList::Node

property fiber : Fiber
property data : T
property state : DeliveryState
Expand All @@ -119,7 +120,8 @@ class Channel(T)

# :nodoc:
struct Receiver(T)
include Crystal::StaticList::Node(self)
include Crystal::PointerLinkedList::Node

property fiber : Fiber
property data : T
property state : DeliveryState
Expand All @@ -135,29 +137,23 @@ class Channel(T)
def initialize(@capacity = 0)
@closed = false

@senders = uninitialized Crystal::StaticList(Sender(T))
@senders.init

@receivers = uninitialized Crystal::StaticList(Receiver(T))
@receivers.init
@senders = Crystal::PointerLinkedList(Sender(T)).new
@receivers = Crystal::PointerLinkedList(Receiver(T)).new

if capacity > 0
@queue = Deque(T).new(capacity)
end
end

def close : Nil
sender_list = uninitialized Crystal::StaticList(Sender(T))
sender_list.init

receiver_list = uninitialized Crystal::StaticList(Receiver(T))
receiver_list.init
sender_list = Crystal::PointerLinkedList(Sender(T)).new
receiver_list = Crystal::PointerLinkedList(Receiver(T)).new

@lock.sync do
@closed = true

@senders.list_append_to pointerof(sender_list)
@receivers.list_append_to pointerof(receiver_list)
@senders.append_to sender_list
@receivers.append_to receiver_list
end

sender_list.each do |sender_ptr|
Expand Down
82 changes: 82 additions & 0 deletions src/crystal/pointer_linked_list.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# :nodoc:
#
# Doubly linked list of `T` structs referenced as pointers.
# `T` that must include `Crystal::PointerLinkedList::Node`.
class Crystal::PointerLinkedList(T)
protected property head : Pointer(T) = Pointer(T).null
protected property tail : Pointer(T) = Pointer(T).null

module Node
macro included
property previous : Pointer({{@type}}) = Pointer({{@type}}).null
property next : Pointer({{@type}}) = Pointer({{@type}}).null
end
end

# Iterates the list.
def each : Nil
node = @head

while !node.null?
yield node
node = node.value.next
end
end

# Appends a node to the tail of the list.
def push(node : Pointer(T)) : Nil
node.value.previous = Pointer(T).null

if (tail = @tail) && !tail.null?
node.value.previous = tail
@tail = tail.value.next = node
else
@head = @tail = node
end
end

# Removes a node from the list.
def delete(node : Pointer(T)) : Nil
if (previous = node.value.previous) && !previous.null?
previous.value.next = node.value.next
else
@head = node.value.next
end

if (_next = node.value.next) && !_next.null?
_next.value.previous = node.value.previous
else
@tail = node.value.previous
end
end

# Removes and returns head from the list, yields if empty
def shift
if head = @head
delete(head)
head
else
yield
end
end

# Returns and returns head from the list, `nil` if empty.
def shift?
shift { nil }
end

# Moves all the nodes from *self* and appends them to *target*
def append_to(target : self)
if (tail = target.tail) && !tail.null?
tail.value.next = @head
@head.value.previous = tail
target.tail = @head
else
target.head = @head
target.tail = @tail
end

@head = Pointer(T).null
@tail = Pointer(T).null
end
end
Loading

0 comments on commit 3dd97bf

Please sign in to comment.