github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/queue.go (about) 1 package task 2 3 import "runtime/interrupt" 4 5 const asserts = false 6 7 // Queue is a FIFO container of tasks. 8 // The zero value is an empty queue. 9 type Queue struct { 10 head, tail *Task 11 } 12 13 // Push a task onto the queue. 14 func (q *Queue) Push(t *Task) { 15 i := interrupt.Disable() 16 if asserts && t.Next != nil { 17 interrupt.Restore(i) 18 panic("runtime: pushing a task to a queue with a non-nil Next pointer") 19 } 20 if q.tail != nil { 21 q.tail.Next = t 22 } 23 q.tail = t 24 t.Next = nil 25 if q.head == nil { 26 q.head = t 27 } 28 interrupt.Restore(i) 29 } 30 31 // Pop a task off of the queue. 32 func (q *Queue) Pop() *Task { 33 i := interrupt.Disable() 34 t := q.head 35 if t == nil { 36 interrupt.Restore(i) 37 return nil 38 } 39 q.head = t.Next 40 if q.tail == t { 41 q.tail = nil 42 } 43 t.Next = nil 44 interrupt.Restore(i) 45 return t 46 } 47 48 // Append pops the contents of another queue and pushes them onto the end of this queue. 49 func (q *Queue) Append(other *Queue) { 50 i := interrupt.Disable() 51 if q.head == nil { 52 q.head = other.head 53 } else { 54 q.tail.Next = other.head 55 } 56 q.tail = other.tail 57 other.head, other.tail = nil, nil 58 interrupt.Restore(i) 59 } 60 61 // Empty checks if the queue is empty. 62 func (q *Queue) Empty() bool { 63 i := interrupt.Disable() 64 empty := q.head == nil 65 interrupt.Restore(i) 66 return empty 67 } 68 69 // Stack is a LIFO container of tasks. 70 // The zero value is an empty stack. 71 // This is slightly cheaper than a queue, so it can be preferable when strict ordering is not necessary. 72 type Stack struct { 73 top *Task 74 } 75 76 // Push a task onto the stack. 77 func (s *Stack) Push(t *Task) { 78 i := interrupt.Disable() 79 if asserts && t.Next != nil { 80 interrupt.Restore(i) 81 panic("runtime: pushing a task to a stack with a non-nil Next pointer") 82 } 83 s.top, t.Next = t, s.top 84 interrupt.Restore(i) 85 } 86 87 // Pop a task off of the stack. 88 func (s *Stack) Pop() *Task { 89 i := interrupt.Disable() 90 t := s.top 91 if t != nil { 92 s.top = t.Next 93 t.Next = nil 94 } 95 interrupt.Restore(i) 96 return t 97 } 98 99 // tail follows the chain of tasks. 100 // If t is nil, returns nil. 101 // Otherwise, returns the task in the chain where the Next field is nil. 102 func (t *Task) tail() *Task { 103 if t == nil { 104 return nil 105 } 106 for t.Next != nil { 107 t = t.Next 108 } 109 return t 110 } 111 112 // Queue moves the contents of the stack into a queue. 113 // Elements can be popped from the queue in the same order that they would be popped from the stack. 114 func (s *Stack) Queue() Queue { 115 i := interrupt.Disable() 116 head := s.top 117 s.top = nil 118 q := Queue{ 119 head: head, 120 tail: head.tail(), 121 } 122 interrupt.Restore(i) 123 return q 124 }