Skip to content

Commit

Permalink
Code, API and Docu improvements (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
mokiat authored Mar 3, 2024
1 parent 2f14f92 commit 746e473
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 4 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
# GoG (Go Generics)

[![Go Reference](https://pkg.go.dev/badge/github.com/mokiat/gog.svg)](https://pkg.go.dev/github.com/mokiat/gog)
[![Go Report Card](https://goreportcard.com/badge/github.com/mokiat/gog)](https://goreportcard.com/report/github.com/mokiat/gog)

GoG is a Go library with useful generic functions and types.

Since the introduction of generics in Go 1.18, a number of useful and reusable
data structures, algorithms and utility functions are now possible. This library
attempts to cover some of the most common use cases.

It does not include functions that are already provided by
[x/exp/slices](https://pkg.go.dev/golang.org/x/exp/slices) and
[x/exp/maps](https://pkg.go.dev/golang.org/x/exp/maps), both of which might
soon be part of the built-in packages.
It avoids duplicating functions that are already provided by
[slices](https://pkg.go.dev/slices) and
[maps](https://pkg.go.dev/maps).

For a complete list on available functions and types, check the
godoc documentation for this project:
Expand Down
23 changes: 23 additions & 0 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ func Map[S, T any](slice []S, fn func(S) T) []T {
return result
}

// MapIndex is similar to Map, except that it passes the element index
// to the closure function as well.
func MapIndex[S, T any](slice []S, fn func(int, S) T) []T {
if slice == nil {
return nil
}
result := make([]T, len(slice))
for i, v := range slice {
result[i] = fn(i, v)
}
return result
}

// Reduce compacts a slice into a single value. The provided function is used
// to perform the reduction starting with the initialValue.
func Reduce[S, T any](slice []S, initialValue T, fn func(accum T, value S) T) T {
Expand Down Expand Up @@ -98,6 +111,14 @@ func Mutate[T any](slice []T, fn func(e *T)) {
}
}

// MutateIndex is similar to Mutate, except that it passes the element index
// to the closure function as well.
func MutateIndex[T any](slice []T, fn func(index int, e *T)) {
for i := range slice {
fn(i, &slice[i])
}
}

// FindFunc iterates over the slice and uses the provided closure function
// to check whether the elements match a user-provided condition. The first
// value that matches is returned as well as a true flag. Otherwise a
Expand Down Expand Up @@ -150,6 +171,8 @@ func DerefElements[T any](slice []*T) []T {
//
// This function always allocates a brand new slice with appropriate
// capacity and never mutates any of the passed slices.
//
// Deprecated: Use built-in slices.Concat instead.
func Concat[T any](slices ...[]T) []T {
capacity := 0
for _, slice := range slices {
Expand Down
42 changes: 42 additions & 0 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ var _ = Describe("Slice", func() {
})
})

Describe("MapIndex", func() {
mapFunc := func(index, v int) string {
return strconv.Itoa(v * index)
}

It("converts from one slice type to another", func() {
source := []int{1, 2, 3}
target := gog.MapIndex(source, mapFunc)
Expect(target).To(Equal([]string{
"0", "2", "6",
}))
})

It("preserves the nil slice", func() {
Expect(gog.MapIndex(nil, mapFunc)).To(Equal([]string(nil)))
})
})

Describe("Reduce", func() {
It("reduces a slice to a single value", func() {
source := []int{1, 2, 3}
Expand Down Expand Up @@ -144,6 +162,30 @@ var _ = Describe("Slice", func() {
})
})

Describe("MutateIndex", func() {
timesIndex := func(index int, v *int) {
*v *= index
}

It("mutates the items of a slice", func() {
slice := []int{1, 2, 3, 4}
gog.MutateIndex(slice, timesIndex)
Expect(slice).To(Equal([]int{0, 2, 6, 12}))
})

It("ignores empty slices", func() {
slice := []int{}
gog.MutateIndex(slice, timesIndex)
Expect(slice).To(Equal([]int{}))
})

It("ignores nil slices", func() {
var slice []int
gog.MutateIndex(slice, timesIndex)
Expect(slice).To(Equal([]int(nil)))
})
})

Describe("FindFunc", func() {
divisibleByFive := func(v int) bool {
return v%5 == 0
Expand Down
7 changes: 7 additions & 0 deletions value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package gog

// Zero returns the zero value of the generic type T.
func Zero[T any]() T {
var zero T
return zero
}
22 changes: 22 additions & 0 deletions value_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package gog_test

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/mokiat/gog"
)

var _ = Describe("Value", func() {

Describe("Zero", func() {

It("returns the zero value", func() {
Expect(gog.Zero[int]()).To(Equal(0))
Expect(gog.Zero[string]()).To(Equal(""))
Expect(gog.Zero[bool]()).To(Equal(false))
})

})

})

0 comments on commit 746e473

Please sign in to comment.