package datastructs import ( "encoding/json" "errors" ) type Queue[T any] struct { head *ChainElem[T] tail *ChainElem[T] } // isValid checks if the queue is still valid. func (q *Queue[T]) isValid() bool { return q.head != nil && q.tail != nil && reachable(q.head, q.tail) } // IsEmpty checks if the queue is empty. func (q *Queue[T]) IsEmpty() bool { return q.head == q.tail } // Push adds a new element to the end of the queue. func (q *Queue[T]) Push(elem *T) error { if !q.isValid() { return errors.New("invalid queue") } e := emptyElem[T]() q.tail.Elem = elem q.tail.Next = e q.tail = e return nil } // Pop removes the first element of the queue. // It errors out if there is no element or the queue is invalid. func (q *Queue[T]) Pop() (*T, error) { if !q.isValid() { return nil, errors.New("invalid queue") } if q.IsEmpty() { return nil, errors.New("empty queue") } Elem := q.head.Elem q.head = q.head.Next return Elem, nil } // Top returns the first element of the queue without removing it. // It errors out if there is no element or the queue is invalid. func (q *Queue[T]) Top() (*T, error) { if !q.isValid() { return nil, errors.New("queue invalid") } if q.IsEmpty() { return nil, errors.New("queue empty") } return q.head.Elem, nil } // HeadElem returns the first ChainElem of the queue without removing it. // It errors out if there is no element or the queue is invalid. func (q *Queue[T]) HeadElem() (*ChainElem[T], error) { if !q.isValid() { return nil, errors.New("queue invalid") } if q.IsEmpty() { return nil, errors.New("queue empty") } return q.head, nil } // MarshalJSON is used for generating json data when using json.Marshal. func (q *Queue[T]) MarshalJSON() ([]byte, error) { if !q.isValid() { return nil, errors.New("queue invalid") } if q.IsEmpty() { return nil, errors.New("queue empty") } return json.Marshal(q.head) } func BuildQueue[T any]() *Queue[T] { empty := emptyElem[T]() return &Queue[T]{ head: empty, tail: empty, } }