Skip to content

Commit 24f8321

Browse files
author
Dean Karn
authored
Add Doubly Linked List and other generics (#20)
1 parent 94bde0f commit 24f8321

File tree

8 files changed

+835
-1
lines changed

8 files changed

+835
-1
lines changed

README.md

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# pkg
22

3-
![Project status](https://img.shields.io/badge/version-5.11.0-green.svg)
3+
![Project status](https://img.shields.io/badge/version-5.12.0-green.svg)
44
[![Build Status](https://travis-ci.org/go-playground/pkg.svg?branch=master)](https://travis-ci.org/go-playground/pkg)
55
[![Coverage Status](https://coveralls.io/repos/github/go-playground/pkg/badge.svg?branch=master)](https://coveralls.io/github/go-playground/pkg?branch=master)
66
[![GoDoc](https://godoc.org/github.com/go-playground/pkg?status.svg)](https://pkg.go.dev/mod/github.com/go-playground/pkg/v5)
@@ -16,6 +16,19 @@ This is a place to put common reusable code that is not quite a library but exte
1616

1717
`go get -u github.com/go-playground/pkg/v5`
1818

19+
20+
## Highlights
21+
- Generic Doubly Linked List.
22+
- Result & Option types
23+
- Generic Mutex and RWMutex.
24+
- Bytes helper placeholders units eg. MB, MiB, GB, ...
25+
- Detachable context.
26+
- Error retryable helper functions.
27+
- Proper RFC3339Nano definition.
28+
- unsafe []byte->string & string->[]byte helper functions.
29+
- HTTP helper functions and constant placeholders.
30+
- And much, much more.
31+
1932
## How to Contribute
2033

2134
Make a pull request... can't guarantee it will be added, going to strictly vet what goes in.

constraints/constraints.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//go:build go1.18
2+
// +build go1.18
3+
4+
package constraintsext
5+
6+
// Number represents any non-complex number eg. Integer and Float.
7+
type Number interface {
8+
Integer | Float
9+
}
10+
11+
// Integer represents any integer type both signed and unsigned.
12+
type Integer interface {
13+
Signed | Unsigned
14+
}
15+
16+
// Float represents any float type.
17+
type Float interface {
18+
~float32 | ~float64
19+
}
20+
21+
// Signed represents any signed integer.
22+
type Signed interface {
23+
~int | ~int8 | ~int16 | ~int32 | ~int64
24+
}
25+
26+
// Unsigned represents any unsigned integer.
27+
type Unsigned interface {
28+
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
29+
}
30+
31+
// Complex represents any complex number type.
32+
type Complex interface {
33+
~complex64 | ~complex128
34+
}

container/list/doubly_linked.go

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
//go:build go1.18
2+
// +build go1.18
3+
4+
package listext
5+
6+
// Node is an element of the doubly linked list.
7+
type Node[V any] struct {
8+
next, prev *Node[V]
9+
value V
10+
}
11+
12+
// Value returns the underlying nodes value.
13+
func (n *Node[V]) Value() V {
14+
return n.value
15+
}
16+
17+
// Next returns the nodes next value or nil if it is at the tail.
18+
func (n *Node[V]) Next() *Node[V] {
19+
return n.next
20+
}
21+
22+
// Prev returns the nodes previous value or nil if it is at the head.
23+
func (n *Node[V]) Prev() *Node[V] {
24+
return n.prev
25+
}
26+
27+
// DoublyLinkedList is a doubly linked list
28+
type DoublyLinkedList[V any] struct {
29+
head, tail *Node[V]
30+
len int
31+
}
32+
33+
// NewDoublyLinked creates a DoublyLinkedList for use.
34+
func NewDoublyLinked[V any]() *DoublyLinkedList[V] {
35+
return new(DoublyLinkedList[V])
36+
}
37+
38+
// PushFront adds an element first in the list.
39+
func (d *DoublyLinkedList[V]) PushFront(v V) *Node[V] {
40+
node := &Node[V]{
41+
value: v,
42+
}
43+
d.pushFront(node)
44+
return d.head
45+
}
46+
47+
func (d *DoublyLinkedList[V]) pushFront(node *Node[V]) {
48+
node.next = d.head
49+
node.prev = nil
50+
51+
if d.head == nil {
52+
d.tail = node
53+
} else {
54+
d.head.prev = node
55+
}
56+
d.head = node
57+
d.len++
58+
}
59+
60+
// PopFront removes the first element and returns it or nil.
61+
func (d *DoublyLinkedList[V]) PopFront() *Node[V] {
62+
if d.IsEmpty() {
63+
return nil
64+
}
65+
66+
node := d.head
67+
d.head = node.next
68+
if d.head == nil {
69+
d.tail = nil
70+
} else {
71+
d.head.prev = nil
72+
}
73+
d.len--
74+
// ensure no leakage
75+
node.next, node.prev = nil, nil
76+
return node
77+
}
78+
79+
// PushBack appends an element to the back of a list.
80+
func (d *DoublyLinkedList[V]) PushBack(v V) *Node[V] {
81+
node := &Node[V]{
82+
value: v,
83+
}
84+
d.pushBack(node)
85+
return d.tail
86+
}
87+
88+
func (d *DoublyLinkedList[V]) pushBack(node *Node[V]) {
89+
node.prev = d.tail
90+
node.next = nil
91+
92+
if d.tail == nil {
93+
d.head = node
94+
} else {
95+
d.tail.next = node
96+
}
97+
d.tail = node
98+
d.len++
99+
}
100+
101+
// PushAfter pushes the supplied value after the supplied node.
102+
//
103+
// The supplied node must be attached to the current list otherwise undefined behaviour could occur.
104+
func (d *DoublyLinkedList[V]) PushAfter(node *Node[V], v V) *Node[V] {
105+
newNode := &Node[V]{
106+
value: v,
107+
}
108+
d.MoveAfter(node, newNode)
109+
return newNode
110+
}
111+
112+
// MoveAfter moves the `moving` node after the supplied `node`.
113+
//
114+
// The supplied `node` must be attached to the current list and the `moving` node must either be attached to the
115+
// current list or not attached to any other otherwise undefined behaviour could occur.
116+
func (d *DoublyLinkedList[V]) MoveAfter(node *Node[V], moving *Node[V]) {
117+
// first detach node were moving after, in case it was already attached somewhere else in the list.
118+
d.Remove(moving)
119+
next := node.next
120+
121+
// no next means node == d.tail
122+
if next == nil {
123+
d.pushBack(moving)
124+
} else {
125+
node.next = moving
126+
moving.prev = node
127+
moving.next = next
128+
next.prev = moving
129+
d.len++
130+
}
131+
}
132+
133+
// PushBefore pushes the supplied value before the supplied node.
134+
//
135+
// The supplied node must be attached to the current list otherwise undefined behaviour could occur.
136+
func (d *DoublyLinkedList[V]) PushBefore(node *Node[V], v V) *Node[V] {
137+
newNode := &Node[V]{
138+
value: v,
139+
}
140+
d.MoveBefore(node, newNode)
141+
return newNode
142+
}
143+
144+
// MoveBefore moves the `moving` node before the supplied `node`.
145+
//
146+
// The supplied `node` must be attached to the current list and the `moving` node must either be attached to the
147+
// current list or not attached to any other otherwise undefined behaviour could occur.
148+
func (d *DoublyLinkedList[V]) MoveBefore(node *Node[V], moving *Node[V]) {
149+
// first detach node were moving after, in case it was already attached somewhere else in the list.
150+
d.Remove(moving)
151+
prev := node.prev
152+
153+
// no prev means node == d.head
154+
if prev == nil {
155+
d.pushFront(moving)
156+
} else {
157+
node.prev = moving
158+
moving.next = node
159+
moving.prev = prev
160+
prev.next = moving
161+
d.len++
162+
}
163+
}
164+
165+
// PopBack removes the last element from a list and returns it or nil.
166+
func (d *DoublyLinkedList[V]) PopBack() *Node[V] {
167+
if d.IsEmpty() {
168+
return nil
169+
}
170+
171+
node := d.tail
172+
d.tail = node.prev
173+
174+
if d.tail == nil {
175+
d.head = nil
176+
} else {
177+
d.tail.next = nil
178+
}
179+
d.len--
180+
// ensure no leakage
181+
node.next, node.prev = nil, nil
182+
return node
183+
}
184+
185+
// Front returns the front/head element for use without removing it or nil list is empty.
186+
func (d *DoublyLinkedList[V]) Front() *Node[V] {
187+
return d.head
188+
}
189+
190+
// Back returns the end/tail element for use without removing it or nil list is empty.
191+
func (d *DoublyLinkedList[V]) Back() *Node[V] {
192+
return d.tail
193+
}
194+
195+
// Remove removes the provided element from the Linked List.
196+
func (d *DoublyLinkedList[V]) Remove(node *Node[V]) {
197+
if node.prev == nil && node.next == nil {
198+
// is a detached node, early exit
199+
return
200+
}
201+
202+
if node.prev == nil {
203+
// is head node
204+
_ = d.PopFront()
205+
} else if node.next == nil {
206+
// is tail node
207+
_ = d.PopBack()
208+
} else {
209+
// is both head and tail nodes, must remap
210+
node.next.prev = node.prev
211+
node.prev.next = node.next
212+
// ensure no leakage
213+
node.next, node.prev = nil, nil
214+
d.len--
215+
}
216+
}
217+
218+
// MoveToFront moves the provided node to the front/head.
219+
func (d *DoublyLinkedList[V]) MoveToFront(node *Node[V]) {
220+
d.Remove(node)
221+
d.pushFront(node)
222+
}
223+
224+
// MoveToBack moves the provided node to the end/tail.
225+
func (d *DoublyLinkedList[V]) MoveToBack(node *Node[V]) {
226+
d.Remove(node)
227+
d.pushBack(node)
228+
}
229+
230+
// IsEmpty returns true if the list is empty.
231+
func (d *DoublyLinkedList[V]) IsEmpty() bool {
232+
return d.len == 0
233+
}
234+
235+
// Len returns length of the Linked List.
236+
func (d *DoublyLinkedList[V]) Len() int {
237+
return d.len
238+
}
239+
240+
// Clear removes all elements from the Linked List.
241+
func (d *DoublyLinkedList[V]) Clear() {
242+
// must loop and clean up references to each other.
243+
for {
244+
if d.PopBack() == nil {
245+
break
246+
}
247+
}
248+
d.head, d.tail, d.len = nil, nil, 0
249+
}

0 commit comments

Comments
 (0)