mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-09-19 12:01:27 +02:00
Merge pull request #8483 from ProofOfKeags/feature/for-loop-destroyer
fn: add slice utilities
This commit is contained in:
@@ -4,5 +4,12 @@ go 1.19
|
||||
|
||||
require (
|
||||
github.com/lightninglabs/neutrino/cache v1.1.2
|
||||
github.com/stretchr/testify v1.8.1
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
13
fn/go.sum
13
fn/go.sum
@@ -1,8 +1,21 @@
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/lightninglabs/neutrino/cache v1.1.2 h1:C9DY/DAPaPxbFC+xNNEI/z1SJY9GS3shmlu5hIQ798g=
|
||||
github.com/lightninglabs/neutrino/cache v1.1.2/go.mod h1:XJNcgdOw1LQnanGjw8Vj44CvguYA25IMKjWFZczwZuo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4=
|
||||
golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
170
fn/slice.go
Normal file
170
fn/slice.go
Normal file
@@ -0,0 +1,170 @@
|
||||
package fn
|
||||
|
||||
// All returns true when the supplied predicate evaluates to true for all of
|
||||
// the values in the slice.
|
||||
func All[A any](pred func(A) bool, s []A) bool {
|
||||
for _, val := range s {
|
||||
if !pred(val) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Any returns true when the supplied predicate evaluates to true for any of
|
||||
// the values in the slice.
|
||||
func Any[A any](pred func(A) bool, s []A) bool {
|
||||
for _, val := range s {
|
||||
if pred(val) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Map applies the function argument to all members of the slice and returns a
|
||||
// slice of those return values.
|
||||
func Map[A, B any](f func(A) B, s []A) []B {
|
||||
res := make([]B, 0, len(s))
|
||||
|
||||
for _, val := range s {
|
||||
res = append(res, f(val))
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Filter creates a new slice of values where all the members of the returned
|
||||
// slice pass the predicate that is supplied in the argument.
|
||||
func Filter[A any](pred func(A) bool, s []A) []A {
|
||||
res := make([]A, 0)
|
||||
|
||||
for _, val := range s {
|
||||
if pred(val) {
|
||||
res = append(res, val)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Foldl iterates through all members of the slice left to right and reduces
|
||||
// them pairwise with an accumulator value that is seeded with the seed value in
|
||||
// the argument.
|
||||
func Foldl[A, B any](f func(B, A) B, seed B, s []A) B {
|
||||
acc := seed
|
||||
|
||||
for _, val := range s {
|
||||
acc = f(acc, val)
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
// Foldr, is exactly like Foldl except that it iterates over the slice from
|
||||
// right to left.
|
||||
func Foldr[A, B any](f func(A, B) B, seed B, s []A) B {
|
||||
acc := seed
|
||||
|
||||
for i := range s {
|
||||
acc = f(s[len(s)-1-i], acc)
|
||||
}
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
// Find returns the first value that passes the supplied predicate, or None if
|
||||
// the value wasn't found.
|
||||
func Find[A any](pred func(A) bool, s []A) Option[A] {
|
||||
for _, val := range s {
|
||||
if pred(val) {
|
||||
return Some(val)
|
||||
}
|
||||
}
|
||||
|
||||
return None[A]()
|
||||
}
|
||||
|
||||
// Flatten takes a slice of slices and returns a concatenation of those slices.
|
||||
func Flatten[A any](s [][]A) []A {
|
||||
sz := Foldr(
|
||||
func(l []A, acc uint64) uint64 {
|
||||
return uint64(len(l)) + acc
|
||||
}, 0, s,
|
||||
)
|
||||
|
||||
res := make([]A, 0, sz)
|
||||
|
||||
for _, val := range s {
|
||||
res = append(res, val...)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Replicate generates a slice of values initialized by the prototype value.
|
||||
func Replicate[A any](n uint, val A) []A {
|
||||
res := make([]A, n)
|
||||
|
||||
for i := range res {
|
||||
res[i] = val
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Span, applied to a predicate and a slice, returns two slices where the first
|
||||
// element is the longest prefix (possibly empty) of slice elements that
|
||||
// satisfy the predicate and second element is the remainder of the slice.
|
||||
func Span[A any](pred func(A) bool, s []A) ([]A, []A) {
|
||||
for i := range s {
|
||||
if !pred(s[i]) {
|
||||
fst := make([]A, i)
|
||||
snd := make([]A, len(s)-i)
|
||||
|
||||
copy(fst, s[:i])
|
||||
copy(snd, s[i:])
|
||||
|
||||
return fst, snd
|
||||
}
|
||||
}
|
||||
|
||||
res := make([]A, len(s))
|
||||
copy(res, s)
|
||||
|
||||
return res, []A{}
|
||||
}
|
||||
|
||||
// SplitAt(n, s) returns a tuple where first element is s prefix of length n
|
||||
// and second element is the remainder of the list.
|
||||
func SplitAt[A any](n uint, s []A) ([]A, []A) {
|
||||
fst := make([]A, n)
|
||||
snd := make([]A, len(s)-int(n))
|
||||
|
||||
copy(fst, s[:n])
|
||||
copy(snd, s[n:])
|
||||
|
||||
return fst, snd
|
||||
}
|
||||
|
||||
// ZipWith combines slice elements with the same index using the function
|
||||
// argument, returning a slice of the results.
|
||||
func ZipWith[A, B, C any](f func(A, B) C, a []A, b []B) []C {
|
||||
var l uint
|
||||
|
||||
if la, lb := len(a), len(b); la < lb {
|
||||
l = uint(la)
|
||||
} else {
|
||||
l = uint(lb)
|
||||
}
|
||||
|
||||
res := make([]C, l)
|
||||
|
||||
for i := 0; i < int(l); i++ {
|
||||
res[i] = f(a[i], b[i])
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
138
fn/slice_test.go
Normal file
138
fn/slice_test.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package fn
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func even(a int) bool { return a%2 == 0 }
|
||||
func odd(a int) bool { return a%2 != 0 }
|
||||
|
||||
func TestAll(t *testing.T) {
|
||||
x := []int{0, 2, 4, 6, 8}
|
||||
require.True(t, All(even, x))
|
||||
require.False(t, All(odd, x))
|
||||
|
||||
y := []int{1, 3, 5, 7, 9}
|
||||
require.False(t, All(even, y))
|
||||
require.True(t, All(odd, y))
|
||||
|
||||
z := []int{0, 2, 4, 6, 9}
|
||||
require.False(t, All(even, z))
|
||||
require.False(t, All(odd, z))
|
||||
}
|
||||
|
||||
func TestAny(t *testing.T) {
|
||||
x := []int{1, 3, 5, 7, 9}
|
||||
require.False(t, Any(even, x))
|
||||
require.True(t, Any(odd, x))
|
||||
|
||||
y := []int{0, 3, 5, 7, 9}
|
||||
require.True(t, Any(even, y))
|
||||
require.True(t, Any(odd, y))
|
||||
|
||||
z := []int{0, 2, 4, 6, 8}
|
||||
require.True(t, Any(even, z))
|
||||
require.False(t, Any(odd, z))
|
||||
}
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
inc := func(i int) int { return i + 1 }
|
||||
|
||||
x := []int{0, 2, 4, 6, 8}
|
||||
|
||||
y := Map(inc, x)
|
||||
|
||||
z := []int{1, 3, 5, 7, 9}
|
||||
|
||||
require.True(t, slices.Equal(y, z))
|
||||
}
|
||||
|
||||
func TestFilter(t *testing.T) {
|
||||
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
|
||||
y := Filter(even, x)
|
||||
|
||||
require.True(t, All(even, y))
|
||||
|
||||
z := Filter(odd, y)
|
||||
|
||||
require.Zero(t, len(z))
|
||||
}
|
||||
|
||||
func TestFoldl(t *testing.T) {
|
||||
seed := []int{}
|
||||
stupid := func(s []int, a int) []int { return append(s, a) }
|
||||
|
||||
x := []int{0, 1, 2, 3, 4}
|
||||
|
||||
r := Foldl(stupid, seed, x)
|
||||
|
||||
require.True(t, slices.Equal(x, r))
|
||||
}
|
||||
|
||||
func TestFoldr(t *testing.T) {
|
||||
seed := []int{}
|
||||
stupid := func(a int, s []int) []int { return append(s, a) }
|
||||
|
||||
x := []int{0, 1, 2, 3, 4}
|
||||
|
||||
z := Foldr(stupid, seed, x)
|
||||
|
||||
slices.Reverse[[]int](x)
|
||||
|
||||
require.True(t, slices.Equal(x, z))
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
x := []int{10, 11, 12, 13, 14, 15}
|
||||
|
||||
div3 := func(a int) bool { return a%3 == 0 }
|
||||
div8 := func(a int) bool { return a%8 == 0 }
|
||||
|
||||
require.Equal(t, Find(div3, x), Some(12))
|
||||
|
||||
require.Equal(t, Find(div8, x), None[int]())
|
||||
}
|
||||
|
||||
func TestFlatten(t *testing.T) {
|
||||
x := [][]int{{0}, {1}, {2}}
|
||||
|
||||
y := Flatten(x)
|
||||
|
||||
require.True(t, slices.Equal(y, []int{0, 1, 2}))
|
||||
}
|
||||
|
||||
func TestReplicate(t *testing.T) {
|
||||
require.True(t, slices.Equal([]int{1, 1, 1, 1, 1}, Replicate(5, 1)))
|
||||
}
|
||||
|
||||
func TestSpan(t *testing.T) {
|
||||
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
lt5 := func(a int) bool { return a < 5 }
|
||||
|
||||
low, high := Span(lt5, x)
|
||||
|
||||
require.True(t, slices.Equal(low, []int{0, 1, 2, 3, 4}))
|
||||
require.True(t, slices.Equal(high, []int{5, 6, 7, 8, 9}))
|
||||
}
|
||||
|
||||
func TestSplitAt(t *testing.T) {
|
||||
x := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||
fst, snd := SplitAt(5, x)
|
||||
|
||||
require.True(t, slices.Equal(fst, []int{0, 1, 2, 3, 4}))
|
||||
require.True(t, slices.Equal(snd, []int{5, 6, 7, 8, 9}))
|
||||
}
|
||||
|
||||
func TestZipWith(t *testing.T) {
|
||||
eq := func(a, b int) bool { return a == b }
|
||||
x := []int{0, 1, 2, 3, 4}
|
||||
y := Replicate(5, 1)
|
||||
z := ZipWith(eq, x, y)
|
||||
require.True(t, slices.Equal(
|
||||
z, []bool{false, true, false, false, false},
|
||||
))
|
||||
}
|
Reference in New Issue
Block a user