ginger/seq/list.go

143 lines
3.1 KiB
Go

package seq
import (
"github.com/mediocregopher/ginger/types"
)
// A List is an implementation of Seq in the form of a single-linked-list, and
// is used as the underlying structure for Seqs for most methods that return a
// Seq. It is probably the most efficient and simplest of the implementations.
// Even though, conceptually, all Seq operations return a new Seq, the old Seq
// can actually share nodes with the new Seq (if both are Lists), thereby saving
// memory and copies.
type List struct {
el types.Elem
next *List
}
// Returns a new List comprised of the given elements (or no elements, for an
// empty list)
func NewList(els ...types.Elem) *List {
elsl := len(els)
if elsl == 0 {
return nil
}
var cur *List
for i := 0; i < elsl; i++ {
cur = &List{els[elsl-i-1], cur}
}
return cur
}
// Implementation of FirstRest for Seq interface. Completes in O(1) time.
func (l *List) FirstRest() (types.Elem, Seq, bool) {
if l == nil {
return nil, l, false
} else {
return l.el, l.next, true
}
}
// Implementation of String for Stringer interface.
func (l *List) String() string {
return ToString(l, "(", ")")
}
// Prepends the given element to the front of the list, returning a copy of the
// new list. Completes in O(1) time.
func (l *List) Prepend(el types.Elem) *List {
return &List{el, l}
}
// Prepends the argument Seq to the beginning of the callee List, returning a
// copy of the new List. Completes in O(N) time, N being the length of the
// argument Seq
func (l *List) PrependSeq(s Seq) *List {
var first, cur, prev *List
var el types.Elem
var ok bool
for {
el, s, ok = s.FirstRest()
if !ok {
break
}
cur = &List{el, nil}
if first == nil {
first = cur
}
if prev != nil {
prev.next = cur
}
prev = cur
}
// prev will be nil if s is empty
if prev == nil {
return l
}
prev.next = l
return first
}
// Appends the given element to the end of the List, returning a copy of the new
// List. While most methods on List don't actually copy much data, this one
// copies the entire list. Completes in O(N) time.
func (l *List) Append(el types.Elem) *List {
var first, cur, prev *List
for l != nil {
cur = &List{l.el, nil}
if first == nil {
first = cur
}
if prev != nil {
prev.next = cur
}
prev = cur
l = l.next
}
final := &List{el, nil}
if prev == nil {
return final
}
prev.next = final
return first
}
// Returns the nth index element (starting at 0), with bool being false if i is
// out of bounds. Completes in O(N) time.
func (l *List) Nth(n uint64) (types.Elem, bool) {
var el types.Elem
var ok bool
s := Seq(l)
for i := uint64(0); ; i++ {
el, s, ok = s.FirstRest()
if !ok {
return nil, false
} else if i == n {
return el, true
}
}
}
// Returns the elements in the Seq as a List. Has similar properties as
// ToSlice. In general this completes in O(N) time. If the given Seq is already
// a List it will complete in O(1) time.
func ToList(s Seq) *List {
var ok bool
var l *List
if l, ok = s.(*List); ok {
return l
}
var el types.Elem
for ret := NewList(); ; {
if el, s, ok = s.FirstRest(); ok {
ret = ret.Prepend(el)
} else {
return Reverse(ret).(*List)
}
}
}