summaryrefslogtreecommitdiff
path: root/vendor/github.com/lann/ps/list.go
blob: 48a1cebacf6aa5ed662777f2d498da276b91da2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package ps

// List is a persistent list of possibly heterogenous values.
type List interface {
	// IsNil returns true if the list is empty
	IsNil() bool

	// Cons returns a new list with val as the head
	Cons(val Any) List

	// Head returns the first element of the list;
	// panics if the list is empty
	Head() Any

	// Tail returns a list with all elements except the head;
	// panics if the list is empty
	Tail() List

	// Size returns the list's length.  This takes O(1) time.
	Size() int

	// ForEach executes a callback for each value in the list.
	ForEach(f func(Any))

	// Reverse returns a list whose elements are in the opposite order as
	// the original list.
	Reverse() List
}

// Immutable (i.e. persistent) list
type list struct {
	depth int // the number of nodes after, and including, this one
	value Any
	tail  *list
}

// An empty list shared by all lists
var nilList = &list{}

// NewList returns a new, empty list.  The result is a singly linked
// list implementation.  All lists share an empty tail, so allocating
// empty lists is efficient in time and memory.
func NewList() List {
	return nilList
}

func (self *list) IsNil() bool {
	return self == nilList
}

func (self *list) Size() int {
	return self.depth
}

func (tail *list) Cons(val Any) List {
	var xs list
	xs.depth = tail.depth + 1
	xs.value = val
	xs.tail = tail
	return &xs
}

func (self *list) Head() Any {
	if self.IsNil() {
		panic("Called Head() on an empty list")
	}

	return self.value
}

func (self *list) Tail() List {
	if self.IsNil() {
		panic("Called Tail() on an empty list")
	}

	return self.tail
}

// ForEach executes a callback for each value in the list
func (self *list) ForEach(f func(Any)) {
	if self.IsNil() {
		return
	}
	f(self.Head())
	self.Tail().ForEach(f)
}

// Reverse returns a list with elements in opposite order as this list
func (self *list) Reverse() List {
	reversed := NewList()
	self.ForEach(func(v Any) { reversed = reversed.Cons(v) })
	return reversed
}