// Copyright (c) 2023 Braydon Kains // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of // the Software, and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. package collections import "errors" type LLNode[T any] struct { Value T Prev *LLNode[T] Next *LLNode[T] } func (head *LLNode[T]) Len() int { curr := head n := 0 for curr != nil { n++ curr = curr.Next } return n } func (head *LLNode[T]) Range() []T { llLen := head.Len() result := make([]T, llLen) curr := head for i := 0; i < llLen; i++ { result[i] = curr.Value curr = curr.Next } return result } func (head *LLNode[T]) AddToTail(val T) *LLNode[T] { curr := head for curr.Next != nil { curr = curr.Next } node := &LLNode[T]{Value: val, Prev: curr} curr.Next = node return node } func (head *LLNode[T]) AddToHead(val T) *LLNode[T] { node := &LLNode[T]{Value: val, Next: head} head.Prev = node return node } func (n *LLNode[T]) RemoveSelf() { if n.Prev != nil { n.Prev.Next = n.Next } if n.Next != nil { n.Next.Prev = n.Prev } } // A FIFO queue. type Queue[T any] struct { Head *LLNode[T] } func (q *Queue[T]) Enqueue(val T) { if q.Head == nil { q.Head = &LLNode[T]{Value: val} } else { q.Head.AddToTail(val) } } var ErrQueueEmpty = errors.New("collections: the queue is empty") func (q *Queue[T]) Dequeue() (T, error) { if q.Head == nil { return *new(T), ErrQueueEmpty } result := q.Head q.Head = result.Next return result.Value, nil } // A Stack, aka FILO queue. type Stack[T any] struct { Head *LLNode[T] } func (s *Stack[T]) Push(val T) { if s.Head == nil { s.Head = &LLNode[T]{Value: val} } else { node := s.Head.AddToHead(val) s.Head = node } } var ErrStackEmpty = errors.New("the stack is empty") func (s *Stack[T]) Pop() (T, error) { if s.Head == nil { return *new(T), ErrStackEmpty } oldHead := s.Head s.Head = s.Head.Next oldHead.RemoveSelf() return oldHead.Value, nil }