Skip to content

Commit 28a0e06

Browse files
Merge pull request #86 from tylertreat-wf/ctrie
Ctrie
2 parents e12c5e2 + a7ad642 commit 28a0e06

File tree

4 files changed

+1294
-0
lines changed

4 files changed

+1294
-0
lines changed

list/persistent.go

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
Copyright 2015 Workiva, LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
/*
18+
Package list provides list implementations. Currently, this includes a
19+
persistent, immutable linked list.
20+
*/
21+
package list
22+
23+
import "errors"
24+
25+
var (
26+
// Empty is an empty PersistentList.
27+
Empty PersistentList = &emptyList{}
28+
29+
// ErrEmptyList is returned when an invalid operation is performed on an
30+
// empty list.
31+
ErrEmptyList = errors.New("Empty list")
32+
)
33+
34+
// PersistentList is an immutable, persistent linked list.
35+
type PersistentList interface {
36+
// Head returns the head of the list. The bool will be false if the list is
37+
// empty.
38+
Head() (interface{}, bool)
39+
40+
// Tail returns the tail of the list. The bool will be false if the list is
41+
// empty.
42+
Tail() (PersistentList, bool)
43+
44+
// IsEmpty indicates if the list is empty.
45+
IsEmpty() bool
46+
47+
// Length returns the number of items in the list.
48+
Length() uint
49+
50+
// Add will add the item to the list, returning the new list.
51+
Add(head interface{}) PersistentList
52+
53+
// Insert will insert the item at the given position, returning the new
54+
// list or an error if the position is invalid.
55+
Insert(val interface{}, pos uint) (PersistentList, error)
56+
57+
// Get returns the item at the given position or an error if the position
58+
// is invalid.
59+
Get(pos uint) (interface{}, bool)
60+
61+
// Remove will remove the item at the given position, returning the new
62+
// list or an error if the position is invalid.
63+
Remove(pos uint) (PersistentList, error)
64+
65+
// Find applies the predicate function to the list and returns the first
66+
// item which matches.
67+
Find(func(interface{}) bool) (interface{}, bool)
68+
69+
// FindIndex applies the predicate function to the list and returns the
70+
// index of the first item which matches or -1 if there is no match.
71+
FindIndex(func(interface{}) bool) int
72+
}
73+
74+
type emptyList struct{}
75+
76+
// Head returns the head of the list. The bool will be false if the list is
77+
// empty.
78+
func (e *emptyList) Head() (interface{}, bool) {
79+
return nil, false
80+
}
81+
82+
// Tail returns the tail of the list. The bool will be false if the list is
83+
// empty.
84+
func (e *emptyList) Tail() (PersistentList, bool) {
85+
return nil, false
86+
}
87+
88+
// IsEmpty indicates if the list is empty.
89+
func (e *emptyList) IsEmpty() bool {
90+
return true
91+
}
92+
93+
// Length returns the number of items in the list.
94+
func (e *emptyList) Length() uint {
95+
return 0
96+
}
97+
98+
// Add will add the item to the list, returning the new list.
99+
func (e *emptyList) Add(head interface{}) PersistentList {
100+
return &list{head, e}
101+
}
102+
103+
// Insert will insert the item at the given position, returning the new list or
104+
// an error if the position is invalid.
105+
func (e *emptyList) Insert(val interface{}, pos uint) (PersistentList, error) {
106+
if pos == 0 {
107+
return e.Add(val), nil
108+
}
109+
return nil, ErrEmptyList
110+
}
111+
112+
// Get returns the item at the given position or an error if the position is
113+
// invalid.
114+
func (e *emptyList) Get(pos uint) (interface{}, bool) {
115+
return nil, false
116+
}
117+
118+
// Remove will remove the item at the given position, returning the new list or
119+
// an error if the position is invalid.
120+
func (e *emptyList) Remove(pos uint) (PersistentList, error) {
121+
return nil, ErrEmptyList
122+
}
123+
124+
// Find applies the predicate function to the list and returns the first item
125+
// which matches.
126+
func (e *emptyList) Find(func(interface{}) bool) (interface{}, bool) {
127+
return nil, false
128+
}
129+
130+
// FindIndex applies the predicate function to the list and returns the index
131+
// of the first item which matches or -1 if there is no match.
132+
func (e *emptyList) FindIndex(func(interface{}) bool) int {
133+
return -1
134+
}
135+
136+
type list struct {
137+
head interface{}
138+
tail PersistentList
139+
}
140+
141+
// Head returns the head of the list. The bool will be false if the list is
142+
// empty.
143+
func (l *list) Head() (interface{}, bool) {
144+
return l.head, true
145+
}
146+
147+
// Tail returns the tail of the list. The bool will be false if the list is
148+
// empty.
149+
func (l *list) Tail() (PersistentList, bool) {
150+
return l.tail, true
151+
}
152+
153+
// IsEmpty indicates if the list is empty.
154+
func (l *list) IsEmpty() bool {
155+
return false
156+
}
157+
158+
// Length returns the number of items in the list.
159+
func (l *list) Length() uint {
160+
curr := l
161+
length := uint(0)
162+
for {
163+
length += 1
164+
tail, _ := curr.Tail()
165+
if tail.IsEmpty() {
166+
return length
167+
}
168+
curr = tail.(*list)
169+
}
170+
}
171+
172+
// Add will add the item to the list, returning the new list.
173+
func (l *list) Add(head interface{}) PersistentList {
174+
return &list{head, l}
175+
}
176+
177+
// Insert will insert the item at the given position, returning the new list or
178+
// an error if the position is invalid.
179+
func (l *list) Insert(val interface{}, pos uint) (PersistentList, error) {
180+
if pos == 0 {
181+
return l.Add(val), nil
182+
}
183+
nl, err := l.tail.Insert(val, pos-1)
184+
if err != nil {
185+
return nil, err
186+
}
187+
return nl.Add(l.head), nil
188+
}
189+
190+
// Get returns the item at the given position or an error if the position is
191+
// invalid.
192+
func (l *list) Get(pos uint) (interface{}, bool) {
193+
if pos == 0 {
194+
return l.head, true
195+
}
196+
return l.tail.Get(pos - 1)
197+
}
198+
199+
// Remove will remove the item at the given position, returning the new list or
200+
// an error if the position is invalid.
201+
func (l *list) Remove(pos uint) (PersistentList, error) {
202+
if pos == 0 {
203+
nl, _ := l.Tail()
204+
return nl, nil
205+
}
206+
207+
nl, err := l.tail.Remove(pos - 1)
208+
if err != nil {
209+
return nil, err
210+
}
211+
return &list{l.head, nl}, nil
212+
}
213+
214+
// Find applies the predicate function to the list and returns the first item
215+
// which matches.
216+
func (l *list) Find(pred func(interface{}) bool) (interface{}, bool) {
217+
if pred(l.head) {
218+
return l.head, true
219+
}
220+
return l.tail.Find(pred)
221+
}
222+
223+
// FindIndex applies the predicate function to the list and returns the index
224+
// of the first item which matches or -1 if there is no match.
225+
func (l *list) FindIndex(pred func(interface{}) bool) int {
226+
curr := l
227+
idx := 0
228+
for {
229+
if pred(curr.head) {
230+
return idx
231+
}
232+
tail, _ := curr.Tail()
233+
if tail.IsEmpty() {
234+
return -1
235+
}
236+
curr = tail.(*list)
237+
idx += 1
238+
}
239+
}

0 commit comments

Comments
 (0)