1+ package txgraph
2+
3+ import (
4+ "container/heap"
5+ "iter"
6+ )
7+
8+ // Stack implements a generic LIFO stack data structure with O(1) Push and Pop.
9+ // The zero value is ready to use.
10+ type Stack [T any ] struct {
11+ items []T
12+ }
13+
14+ // NewStack creates a new empty stack with optional initial capacity.
15+ func NewStack [T any ](capacity ... int ) * Stack [T ] {
16+ cap := 0
17+ if len (capacity ) > 0 {
18+ cap = capacity [0 ]
19+ }
20+ return & Stack [T ]{
21+ items : make ([]T , 0 , cap ),
22+ }
23+ }
24+
25+ // Push adds an item to the top of the stack.
26+ func (s * Stack [T ]) Push (item T ) {
27+ s .items = append (s .items , item )
28+ }
29+
30+ // Pop removes and returns the item at the top of the stack.
31+ // Returns false if the stack is empty.
32+ func (s * Stack [T ]) Pop () (T , bool ) {
33+ if len (s .items ) == 0 {
34+ var zero T
35+ return zero , false
36+ }
37+ idx := len (s .items ) - 1
38+ item := s .items [idx ]
39+ s .items = s .items [:idx ]
40+ return item , true
41+ }
42+
43+ // Peek returns the item at the top of the stack without removing it.
44+ // Returns false if the stack is empty.
45+ func (s * Stack [T ]) Peek () (T , bool ) {
46+ if len (s .items ) == 0 {
47+ var zero T
48+ return zero , false
49+ }
50+ return s .items [len (s .items )- 1 ], true
51+ }
52+
53+ // Len returns the number of items in the stack.
54+ func (s * Stack [T ]) Len () int {
55+ return len (s .items )
56+ }
57+
58+ // IsEmpty returns true if the stack contains no items.
59+ func (s * Stack [T ]) IsEmpty () bool {
60+ return len (s .items ) == 0
61+ }
62+
63+ // Clear removes all items from the stack.
64+ func (s * Stack [T ]) Clear () {
65+ s .items = s .items [:0 ]
66+ }
67+
68+ // Iterate returns an iterator that yields items from top to bottom without
69+ // modifying the stack.
70+ func (s * Stack [T ]) Iterate () iter.Seq [T ] {
71+ return func (yield func (T ) bool ) {
72+ for i := len (s .items ) - 1 ; i >= 0 ; i -- {
73+ if ! yield (s .items [i ]) {
74+ return
75+ }
76+ }
77+ }
78+ }
79+
80+ // Queue implements a generic FIFO queue with amortized O(1) Enqueue and
81+ // Dequeue operations. The zero value is ready to use.
82+ type Queue [T any ] struct {
83+ items []T
84+ }
85+
86+ // NewQueue creates a new empty queue with optional initial capacity.
87+ func NewQueue [T any ](capacity ... int ) * Queue [T ] {
88+ cap := 0
89+ if len (capacity ) > 0 {
90+ cap = capacity [0 ]
91+ }
92+ return & Queue [T ]{
93+ items : make ([]T , 0 , cap ),
94+ }
95+ }
96+
97+ // Enqueue adds an item to the back of the queue.
98+ func (q * Queue [T ]) Enqueue (item T ) {
99+ q .items = append (q .items , item )
100+ }
101+
102+ // Dequeue removes and returns the item at the front of the queue.
103+ // Returns false if the queue is empty.
104+ func (q * Queue [T ]) Dequeue () (T , bool ) {
105+ if len (q .items ) == 0 {
106+ var zero T
107+ return zero , false
108+ }
109+ item := q .items [0 ]
110+ q .items = q .items [1 :]
111+ return item , true
112+ }
113+
114+ // Peek returns the item at the front of the queue without removing it.
115+ // Returns false if the queue is empty.
116+ func (q * Queue [T ]) Peek () (T , bool ) {
117+ if len (q .items ) == 0 {
118+ var zero T
119+ return zero , false
120+ }
121+ return q .items [0 ], true
122+ }
123+
124+ // Len returns the number of items in the queue.
125+ func (q * Queue [T ]) Len () int {
126+ return len (q .items )
127+ }
128+
129+ // IsEmpty returns true if the queue contains no items.
130+ func (q * Queue [T ]) IsEmpty () bool {
131+ return len (q .items ) == 0
132+ }
133+
134+ // Clear removes all items from the queue.
135+ func (q * Queue [T ]) Clear () {
136+ q .items = q .items [:0 ]
137+ }
138+
139+ // Iterate returns an iterator that yields items from front to back without
140+ // modifying the queue.
141+ func (q * Queue [T ]) Iterate () iter.Seq [T ] {
142+ return func (yield func (T ) bool ) {
143+ for _ , item := range q .items {
144+ if ! yield (item ) {
145+ return
146+ }
147+ }
148+ }
149+ }
150+
151+ // PriorityQueue implements a generic priority queue using container/heap
152+ // ordered by a comparison function. The zero value is NOT ready to use;
153+ // use NewPriorityQueue to create an instance.
154+ type PriorityQueue [T any ] struct {
155+ impl * heapImpl [T ]
156+ }
157+
158+ // NewPriorityQueue creates a new priority queue with the given comparison
159+ // function where less(a, b) returns true if a has higher priority than b.
160+ // For a max-heap use: func(a, b) { return a > b }.
161+ func NewPriorityQueue [T any ](
162+ less func (a , b T ) bool ,
163+ capacity ... int ,
164+ ) * PriorityQueue [T ] {
165+
166+ cap := 0
167+ if len (capacity ) > 0 {
168+ cap = capacity [0 ]
169+ }
170+ return & PriorityQueue [T ]{
171+ impl : & heapImpl [T ]{
172+ items : make ([]T , 0 , cap ),
173+ less : less ,
174+ },
175+ }
176+ }
177+
178+ // Push adds an item to the priority queue.
179+ func (pq * PriorityQueue [T ]) Push (item T ) {
180+ heap .Push (pq .impl , item )
181+ }
182+
183+ // Pop removes and returns the highest priority item from the queue.
184+ // Returns false if the queue is empty.
185+ func (pq * PriorityQueue [T ]) Pop () (T , bool ) {
186+ if pq .impl .Len () == 0 {
187+ var zero T
188+ return zero , false
189+ }
190+ return heap .Pop (pq .impl ).(T ), true
191+ }
192+
193+ // Peek returns the highest priority item without removing it.
194+ // Returns false if the queue is empty.
195+ func (pq * PriorityQueue [T ]) Peek () (T , bool ) {
196+ if pq .impl .Len () == 0 {
197+ var zero T
198+ return zero , false
199+ }
200+ return pq .impl .items [0 ], true
201+ }
202+
203+ // Len returns the number of items in the priority queue.
204+ func (pq * PriorityQueue [T ]) Len () int {
205+ return pq .impl .Len ()
206+ }
207+
208+ // IsEmpty returns true if the priority queue contains no items.
209+ func (pq * PriorityQueue [T ]) IsEmpty () bool {
210+ return pq .impl .Len () == 0
211+ }
212+
213+ // Clear removes all items from the priority queue.
214+ func (pq * PriorityQueue [T ]) Clear () {
215+ pq .impl .items = pq .impl .items [:0 ]
216+ }
217+
218+ // Iterate returns an iterator that yields items in priority order by
219+ // creating a temporary copy to avoid modifying the original queue.
220+ func (pq * PriorityQueue [T ]) Iterate () iter.Seq [T ] {
221+ return func (yield func (T ) bool ) {
222+ tmpItems := make ([]T , len (pq .impl .items ))
223+ copy (tmpItems , pq .impl .items )
224+ tmp := & PriorityQueue [T ]{
225+ impl : & heapImpl [T ]{
226+ items : tmpItems ,
227+ less : pq .impl .less ,
228+ },
229+ }
230+
231+ for ! tmp .IsEmpty () {
232+ item , _ := tmp .Pop ()
233+ if ! yield (item ) {
234+ return
235+ }
236+ }
237+ }
238+ }
239+
240+ // heapImpl implements heap.Interface to integrate with container/heap.
241+ type heapImpl [T any ] struct {
242+ items []T
243+ less func (a , b T ) bool
244+ }
245+
246+ func (h * heapImpl [T ]) Len () int {
247+ return len (h .items )
248+ }
249+
250+ func (h * heapImpl [T ]) Less (i , j int ) bool {
251+ return h .less (h .items [i ], h .items [j ])
252+ }
253+
254+ func (h * heapImpl [T ]) Swap (i , j int ) {
255+ h .items [i ], h .items [j ] = h .items [j ], h .items [i ]
256+ }
257+
258+ func (h * heapImpl [T ]) Push (x any ) {
259+ h .items = append (h .items , x .(T ))
260+ }
261+
262+ func (h * heapImpl [T ]) Pop () any {
263+ n := len (h .items ) - 1
264+ item := h .items [n ]
265+ h .items = h .items [:n ]
266+ return item
267+ }
268+
269+ var _ heap.Interface = (* heapImpl [int ])(nil )
0 commit comments