Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion collections/btree/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (self *TreeMap[TKey, TValue]) Get(key TKey) optional.Optional[TValue] {

// GetDefault returns the value for the given key or the default value.
func (self *TreeMap[TKey, TValue]) GetDefault(key TKey, value TValue) TValue {
return self.Get(key).OrElse(value)
return self.Get(key).ValueOr(value)
}

// GetEntry returns the MapEntry for the given key.
Expand Down
79 changes: 70 additions & 9 deletions optional/optional.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ func (self Optional[T]) IsSome() bool { return self.data != nil }
// IsNone returns true if the Optional is None.
func (self Optional[T]) IsNone() bool { return !self.IsSome() }

// IsSomeAnd returns true if the Optional is Some and satisfies the given predicate.
func (self Optional[T]) IsSomeAnd(predicate func(T) bool) bool {
if self.IsSome() {
return predicate(*self.data)
}
return false
}

// Value returns the value of the Optional.
func (self Optional[T]) Value() T {
if self.IsSome() {
Expand All @@ -45,25 +53,58 @@ func (self Optional[T]) Value() T {
panic("Unwrap empty value")
}

// ValueOr returns the Optional if it is Some, otherwise returns the given default value.
func (self Optional[T]) ValueOr(defaultValue T) T {
if self.IsSome() {
return self.Value()
}
return defaultValue
}

// ValueOrElse returns the Optional if it is Some, otherwise returns the given default value.
func (self Optional[T]) ValueOrElse(defaultFunc func() T) T {
if self.IsSome() {
return self.Value()
}
return defaultFunc()
}

// ValueOrZero returns the Optional if it is Some, otherwise returns the zero value of the type.
func (self Optional[T]) ValueOrZero() T {
var zero T
return self.ValueOr(zero)
}

// And returns None if the option is None, otherwise returns given opt.
func (self Optional[T]) And(opt Optional[T]) Optional[T] {
if self.IsSome() {
return opt
}
return None[T]()
}

// AndThen returns None if the option is None, otherwise calls f with the wrapped value and returns the result.
func (self Optional[T]) AndThen(f func(T) Optional[T]) Optional[T] {
if self.IsSome() {
return f(*self.data)
}
return None[T]()
}

// Or returns the given opt if the option is None, otherwise returns the option.
func (self Optional[T]) Or(opt Optional[T]) Optional[T] {
if self.IsNone() {
return opt
}
return self
}

func (self Optional[T]) OrElse(defaultValue T) T {
// OrElse returns the Optional if it contains a value, otherwise calls f and returns the result.
func (self Optional[T]) OrElse(f func() Optional[T]) Optional[T] {
if self.IsSome() {
return self.Value()
return Some(*self.data)
}
return defaultValue
return f()
}

func (self Optional[T]) IfPresent(consume func(T)) {
Expand All @@ -79,14 +120,34 @@ func (self Optional[T]) Filter(fn func(T) bool) Optional[T] {
return None[T]()
}

func (self Optional[T]) Map(mapFn func(T) T) Optional[T] {
return Map(self, mapFn)
// Map returns None if the option is None, otherwise calls the given function and returns the result.
func (self Optional[T]) Map(f func(T) T) Optional[T] {
return Map(self, f)
}

func (self Optional[T]) OrZero() T {
// MapOr returns None if the option is None, otherwise calls the given function and returns the result.
func (self Optional[T]) MapOr(defaultValue T, f func(T) T) T {
if self.IsSome() {
return self.Value()
return f(self.Value())
}
var zero T
return zero
return defaultValue
}

// MapOrElse returns None if the option is None, otherwise calls the given function and returns the result.
func (self Optional[T]) MapOrElse(df func() T, f func(T) T) T {
if self.IsSome() {
return f(self.Value())
}
return df()
}

// Xor returns None if the option is None, otherwise returns the given opt.
func (self Optional[T]) Xor(opt Optional[T]) Optional[T] {
if self.IsSome() && opt.IsNone() {
return Some(*self.data)
}
if self.IsNone() && opt.IsSome() {
return Some(*opt.data)
}
return None[T]()
}
125 changes: 125 additions & 0 deletions optional/optional_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package optional_test

import (
"github.com/frankban/quicktest"
"github.com/go-board/std/optional"
"testing"
)

func TestCtor(t *testing.T) {
a := quicktest.New(t)

a.Run("some", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.IsSome(), quicktest.IsTrue)
})
a.Run("none", func(c *quicktest.C) {
x := optional.None[int]()
c.Assert(x.IsNone(), quicktest.IsTrue)
})

a.Run("some_and", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.IsSomeAnd(func(i int) bool { return i == 100 }), quicktest.IsTrue)
y := optional.None[int]()
c.Assert(y.IsSomeAnd(func(i int) bool { return i == 100 }), quicktest.IsFalse)
z := optional.Some(200)
c.Assert(z.IsSomeAnd(func(i int) bool { return i == 100 }), quicktest.IsFalse)
})
}

func TestValue(t *testing.T) {
a := quicktest.New(t)

a.Run("value", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.Value(), quicktest.Equals, 100)
y := optional.None[int]()
c.Assert(func() { y.Value() }, quicktest.PanicMatches, "Unwrap empty value")
})

a.Run("value_or", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.ValueOr(200), quicktest.Equals, 100)
y := optional.None[int]()
c.Assert(y.ValueOr(200), quicktest.Equals, 200)
})

a.Run("value_or_else", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.ValueOrElse(func() int { return 200 }), quicktest.Equals, 100)
y := optional.None[int]()
c.Assert(y.ValueOrElse(func() int { return 200 }), quicktest.Equals, 200)
})

a.Run("value_or_zero", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.ValueOrZero(), quicktest.Equals, 100)
y := optional.None[int]()
c.Assert(y.ValueOrZero(), quicktest.Equals, 0)
})
}

func TestBitOp(t *testing.T) {
a := quicktest.New(t)

a.Run("and", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.And(optional.Some(200)).Value(), quicktest.Equals, 200)
y := optional.None[int]()
c.Assert(y.And(optional.Some(200)).IsNone(), quicktest.IsTrue)
z := optional.Some(200)
c.Assert(x.And(z).Value(), quicktest.Equals, 200)
})
a.Run("and_then", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.AndThen(func(i int) optional.Optional[int] { return optional.Some(i * 2) }).Value(), quicktest.Equals, 200)
y := optional.None[int]()
c.Assert(y.AndThen(func(i int) optional.Optional[int] { return optional.Some(i * 2) }).IsNone(), quicktest.IsTrue)
})
a.Run("or", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.Or(optional.Some(200)).Value(), quicktest.Equals, 100)
y := optional.None[int]()
c.Assert(y.Or(optional.Some(200)).Value(), quicktest.Equals, 200)
z := optional.Some(200)
c.Assert(x.Or(z).Value(), quicktest.Equals, 100)
})
a.Run("or_else", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.OrElse(func() optional.Optional[int] { return optional.Some(200) }).Value(), quicktest.Equals, 100)
y := optional.None[int]()
c.Assert(y.OrElse(func() optional.Optional[int] { return optional.Some(200) }).Value(), quicktest.Equals, 200)
})

a.Run("xor", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.Xor(optional.Some(200)).IsNone(), quicktest.IsTrue)
y := optional.None[int]()
c.Assert(y.Xor(optional.Some(200)).IsSome(), quicktest.IsTrue)
z := optional.Some(200)
c.Assert(x.Xor(z).IsSome(), quicktest.IsFalse)
})
}

func TestMap(t *testing.T) {
a := quicktest.New(t)
a.Run("map", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.Map(func(i int) int { return i * 2 }).Value(), quicktest.Equals, 200)
y := optional.None[int]()
c.Assert(y.Map(func(i int) int { return i * 2 }).IsNone(), quicktest.IsTrue)
})
a.Run("map_or", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.MapOr(300, func(i int) int { return i * 2 }), quicktest.Equals, 200)
y := optional.None[int]()
c.Assert(y.MapOr(300, func(i int) int { return i * 2 }), quicktest.Equals, 300)
})
a.Run("map_or_else", func(c *quicktest.C) {
x := optional.Some(100)
c.Assert(x.MapOrElse(func() int { return 300 }, func(i int) int { return i * 2 }), quicktest.Equals, 200)
y := optional.None[int]()
c.Assert(y.MapOrElse(func() int { return 300 }, func(i int) int { return i * 2 }), quicktest.Equals, 300)
})
}
4 changes: 2 additions & 2 deletions slices/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ func FilterIndexed[T any](slice []T, f func(T, int) bool) []T {
// FindIndex returns the index of the first element in the given slice that satisfies the given predicate.
// Deprecated: use Index instead.
func FindIndex[T comparable](slice []T, v T) int {
return Index(slice, v).OrElse(-1)
return Index(slice, v).ValueOr(-1)
}

// FindIndexBy returns the index of the first element in the given slice that satisfies the given predicate.
// Deprecated: use IndexBy instead.
func FindIndexBy[T any](slice []T, v T, eq func(T, T) bool) int {
return IndexBy(slice, v, eq).OrElse(-1)
return IndexBy(slice, v, eq).ValueOr(-1)
}

// Flatten returns a new slice with all elements in the given slice and all elements in all sub-slices.
Expand Down