go/mqtt/internal/appendable_list_with_removal.go (60 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. package internal import ( "iter" "sync" ) type listNode[T any] struct { value T prev *listNode[T] next *listNode[T] } type AppendableListWithRemoval[T any] struct { mu sync.RWMutex first *listNode[T] last *listNode[T] } func NewAppendableListWithRemoval[T any]() *AppendableListWithRemoval[T] { return &AppendableListWithRemoval[T]{} } func (l *AppendableListWithRemoval[T]) AppendEntry( value T, ) (removeEntry func()) { l.mu.Lock() defer l.mu.Unlock() node := &listNode[T]{value: value} if l.last == nil { l.first = node } else { l.last.next = node } node.prev = l.last l.last = node return func() { l.mu.Lock() defer l.mu.Unlock() if node == nil { // Node was already deleted. return } if node.prev == nil { l.first = node.next } else { node.prev.next = node.next } if node.next == nil { l.last = node.prev } else { node.next.prev = node.prev } // Set this to nil so the node can be garbage collected. node = nil } } func (l *AppendableListWithRemoval[T]) All() iter.Seq[T] { return func(yield func(T) bool) { l.mu.RLock() defer l.mu.RUnlock() curr := l.first for curr != nil && yield(curr.value) { curr = curr.next } } }