Skip to content

Commit 364d79e

Browse files
committed
fn: add generic version of List
1 parent fb1437c commit 364d79e

File tree

2 files changed

+1031
-0
lines changed

2 files changed

+1031
-0
lines changed

fn/list.go

Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
// Copyright (c) 2009 The Go Authors. All rights reserved.
2+
// Copyright (c) 2024 Lightning Labs and the Lightning Network Developers
3+
4+
// Redistribution and use in source and binary forms, with or without
5+
// modification, are permitted provided that the following conditions are
6+
// met:
7+
8+
// * Redistributions of source code must retain the above copyright
9+
// notice, this list of conditions and the following disclaimer.
10+
// * Redistributions in binary form must reproduce the above
11+
// copyright notice, this list of conditions and the following disclaimer
12+
// in the documentation and/or other materials provided with the
13+
// distribution.
14+
// * Neither the name of Google Inc. nor the names of its
15+
// contributors may be used to endorse or promote products derived from
16+
// this software without specific prior written permission.
17+
18+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
package fn
30+
31+
type Node[A any] struct {
32+
// prev is a pointer to the previous node in the List.
33+
prev *Node[A]
34+
35+
// next is a pointer to the next node in the List.
36+
next *Node[A]
37+
38+
// list is the root pointer to the List in which this node is located.
39+
list *List[A]
40+
41+
// Value is the actual data contained within the Node.
42+
Value A
43+
}
44+
45+
// Next returns the next list node or nil.
46+
func (e *Node[A]) Next() *Node[A] {
47+
if e.list == nil {
48+
return nil
49+
}
50+
51+
if e.next == &e.list.root {
52+
return nil
53+
}
54+
55+
return e.next
56+
}
57+
58+
// Prev returns the previous list node or nil.
59+
func (e *Node[A]) Prev() *Node[A] {
60+
if e.list == nil {
61+
return nil
62+
}
63+
64+
if e.prev == &e.list.root {
65+
return nil
66+
}
67+
68+
return e.prev
69+
}
70+
71+
// List represents a doubly linked list.
72+
// The zero value for List is an empty list ready to use.
73+
type List[A any] struct {
74+
// root is a sentinal Node to identify the head and tail of the list.
75+
// root.prev is the tail, root.next is the head. For the purposes of
76+
// elegance, the absence of a next or prev node is encoded as the
77+
// address of the root node.
78+
root Node[A]
79+
80+
// len is the current length of the list.
81+
len int
82+
}
83+
84+
// Init intializes or clears the List l.
85+
func (l *List[A]) Init() *List[A] {
86+
l.root.next = &l.root
87+
l.root.prev = &l.root
88+
l.len = 0
89+
90+
return l
91+
}
92+
93+
// lazyInit lazily initializes a zero List value. It is called by other public
94+
// functions that could feasibly be called on a List that was initialized by the
95+
// raw List[A]{} constructor.
96+
func (l *List[A]) lazyInit() {
97+
if l.root.next == nil {
98+
l.Init()
99+
}
100+
}
101+
102+
// insert inserts n after predecessor, increments l.len, and returns n.
103+
func (l *List[A]) insert(n *Node[A], predecessor *Node[A]) *Node[A] {
104+
// Make n point to correct neighborhood.
105+
n.prev = predecessor
106+
n.next = predecessor.next
107+
108+
// Make neighborhood point to n.
109+
n.prev.next = n
110+
n.next.prev = n
111+
112+
// Make n part of the list.
113+
n.list = l
114+
115+
// Increment list length.
116+
l.len++
117+
118+
return n
119+
}
120+
121+
// insertVal is a convenience wrapper for
122+
// insert(&Node[A]{Value: v}, predecessor).
123+
func (l *List[A]) insertVal(a A, predecessor *Node[A]) *Node[A] {
124+
return l.insert(&Node[A]{Value: a}, predecessor)
125+
}
126+
127+
// move removes n from its current position and inserts it as the successor to
128+
// predecessor.
129+
func (l *List[A]) move(n *Node[A], predecessor *Node[A]) {
130+
if n == predecessor {
131+
return // Can't move after itself.
132+
}
133+
134+
if predecessor.next == n {
135+
return // Nothing to be done.
136+
}
137+
138+
// Bind previous and next to each other.
139+
n.prev.next = n.next
140+
n.next.prev = n.prev
141+
142+
// Make n point to new neighborhood.
143+
n.prev = predecessor
144+
n.next = predecessor.next
145+
146+
// Make new neighborhood point to n.
147+
n.prev.next = n
148+
n.next.prev = n
149+
}
150+
151+
// New returns an initialized List.
152+
func NewList[A any]() *List[A] {
153+
l := List[A]{}
154+
return l.Init()
155+
}
156+
157+
// Len returns the number of elements of List l.
158+
// The complexity is O(1).
159+
func (l *List[A]) Len() int {
160+
return l.len
161+
}
162+
163+
// Front returns the first Node of List l or nil if the list is empty.
164+
func (l *List[A]) Front() *Node[A] {
165+
if l.len == 0 {
166+
return nil
167+
}
168+
169+
return l.root.next
170+
}
171+
172+
// Back returns the last Node of List l or nil if the list is empty.
173+
func (l *List[A]) Back() *Node[A] {
174+
if l.len == 0 {
175+
return nil
176+
}
177+
178+
return l.root.prev
179+
}
180+
181+
// Remove removes Node n from List l if n is an element of List l.
182+
// It returns the Node value e.Value.
183+
// The Node must not be nil.
184+
func (l *List[A]) Remove(n *Node[A]) A {
185+
if n.list == l {
186+
n.prev.next = n.next
187+
n.next.prev = n.prev
188+
l.len--
189+
190+
v := n.Value
191+
// Set all node data to nil to prevent dangling references.
192+
*n = Node[A]{Value: v}
193+
194+
return v
195+
}
196+
197+
return n.Value
198+
}
199+
200+
// PushFront inserts a new Node n with value a at the front of List l and
201+
// returns n.
202+
func (l *List[A]) PushFront(a A) *Node[A] {
203+
l.lazyInit()
204+
return l.insertVal(a, &l.root)
205+
}
206+
207+
// PushBack inserts a new Node n with value a at the back of List l and returns
208+
// n.
209+
func (l *List[A]) PushBack(a A) *Node[A] {
210+
l.lazyInit()
211+
return l.insertVal(a, l.root.prev)
212+
}
213+
214+
// InsertBefore inserts a new Node n with value a immediately before successor
215+
// and returns n. If successor is not an element of l, the list is not
216+
// modified. The successor must not be nil.
217+
func (l *List[A]) InsertBefore(a A, successor *Node[A]) *Node[A] {
218+
if successor == nil {
219+
return l.insertVal(a, &l.root)
220+
}
221+
222+
if successor.list != l {
223+
return nil
224+
}
225+
226+
return l.insertVal(a, successor.prev)
227+
}
228+
229+
// InsertAfter inserts a new Node n with value a immediately after and returns
230+
// e. If predecessor is not an element of l, the list is not modified. The
231+
// predecessor must not be nil.
232+
func (l *List[A]) InsertAfter(a A, predecessor *Node[A]) *Node[A] {
233+
if predecessor == nil {
234+
return l.insertVal(a, l.root.prev)
235+
}
236+
237+
if predecessor.list != l {
238+
return nil
239+
}
240+
241+
return l.insertVal(a, predecessor)
242+
}
243+
244+
// MoveToFront moves Node n to the front of List l.
245+
// If n is not an element of l, the list is not modified.
246+
// The Node must not be nil.
247+
func (l *List[A]) MoveToFront(n *Node[A]) {
248+
if n.list == l {
249+
l.move(n, &l.root)
250+
}
251+
}
252+
253+
// MoveToBack moves Node n to the back of List l.
254+
// If n is not an element of l, the list is not modified.
255+
// The Node must not be nil.
256+
func (l *List[A]) MoveToBack(n *Node[A]) {
257+
if n.list == l {
258+
l.move(n, l.root.prev)
259+
}
260+
}
261+
262+
// MoveBefore moves Node n to its new position before successor.
263+
// If n or successor is not an element of l, or n == successor, the list is not
264+
// modified. The Node and successor must not be nil.
265+
func (l *List[A]) MoveBefore(n, successor *Node[A]) {
266+
if n.list == l && successor.list == l {
267+
l.move(n, successor.prev)
268+
}
269+
}
270+
271+
// MoveAfter moves Node n to its new position after predecessor.
272+
// If n or predecessor is not an element of l, or n == predecessor, the list is
273+
// not modified. The Node and predecessor must not be nil.
274+
func (l *List[A]) MoveAfter(n, predecessor *Node[A]) {
275+
if n.list == l && predecessor.list == l {
276+
l.move(n, predecessor)
277+
}
278+
}
279+
280+
// PushBackList inserts a copy of List other at the back of List l.
281+
// The Lists l and other may be the same. They must not be nil.
282+
func (l *List[A]) PushBackList(other *List[A]) {
283+
l.lazyInit()
284+
n := other.Front()
285+
sz := other.Len()
286+
for i := 0; i < sz; i++ {
287+
l.insertVal(n.Value, l.root.prev)
288+
n = n.Next()
289+
}
290+
}
291+
292+
// PushFrontList inserts a copy of List other at the front of List l.
293+
// The Lists l and other may be the same. They must not be nil.
294+
func (l *List[A]) PushFrontList(other *List[A]) {
295+
l.lazyInit()
296+
n := other.Back()
297+
sz := other.Len()
298+
for i := 0; i < sz; i++ {
299+
l.insertVal(n.Value, &l.root)
300+
n = n.Prev()
301+
}
302+
}

0 commit comments

Comments
 (0)