github.com/jackc/puddle/v2@v2.2.2-0.20240301145809-72b022bcfc59/internal/genstack/gen_stack.go (about) 1 package genstack 2 3 // GenStack implements a generational stack. 4 // 5 // GenStack works as common stack except for the fact that all elements in the 6 // older generation are guaranteed to be popped before any element in the newer 7 // generation. New elements are always pushed to the current (newest) 8 // generation. 9 // 10 // We could also say that GenStack behaves as a stack in case of a single 11 // generation, but it behaves as a queue of individual generation stacks. 12 type GenStack[T any] struct { 13 // We can represent arbitrary number of generations using 2 stacks. The 14 // new stack stores all new pushes and the old stack serves all reads. 15 // Old stack can represent multiple generations. If old == new, then all 16 // elements pushed in previous (not current) generations have already 17 // been popped. 18 19 old *stack[T] 20 new *stack[T] 21 } 22 23 // NewGenStack creates a new empty GenStack. 24 func NewGenStack[T any]() *GenStack[T] { 25 s := &stack[T]{} 26 return &GenStack[T]{ 27 old: s, 28 new: s, 29 } 30 } 31 32 func (s *GenStack[T]) Pop() (T, bool) { 33 // Pushes always append to the new stack, so if the old once becomes 34 // empty, it will remail empty forever. 35 if s.old.len() == 0 && s.old != s.new { 36 s.old = s.new 37 } 38 39 if s.old.len() == 0 { 40 var zero T 41 return zero, false 42 } 43 44 return s.old.pop(), true 45 } 46 47 // Push pushes a new element at the top of the stack. 48 func (s *GenStack[T]) Push(v T) { s.new.push(v) } 49 50 // NextGen starts a new stack generation. 51 func (s *GenStack[T]) NextGen() { 52 if s.old == s.new { 53 s.new = &stack[T]{} 54 return 55 } 56 57 // We need to pop from the old stack to the top of the new stack. Let's 58 // have an example: 59 // 60 // Old: <bottom> 4 3 2 1 61 // New: <bottom> 8 7 6 5 62 // PopOrder: 1 2 3 4 5 6 7 8 63 // 64 // 65 // To preserve pop order, we have to take all elements from the old 66 // stack and push them to the top of new stack: 67 // 68 // New: 8 7 6 5 4 3 2 1 69 // 70 s.new.push(s.old.takeAll()...) 71 72 // We have the old stack allocated and empty, so why not to reuse it as 73 // new new stack. 74 s.old, s.new = s.new, s.old 75 } 76 77 // Len returns number of elements in the stack. 78 func (s *GenStack[T]) Len() int { 79 l := s.old.len() 80 if s.old != s.new { 81 l += s.new.len() 82 } 83 84 return l 85 }