Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slicesandmaps #206

Merged
merged 5 commits into from
Aug 31, 2023
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 VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.78.4
1.79.0
2 changes: 1 addition & 1 deletion examples/service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.21
replace github.com/Vonage/gosrvlib => ../..

require (
github.com/Vonage/gosrvlib v1.78.4
github.com/Vonage/gosrvlib v1.79.0
github.com/golang/mock v1.6.0
github.com/jstemmer/go-junit-report v0.9.1
github.com/prometheus/client_golang v1.16.0
Expand Down
57 changes: 57 additions & 0 deletions pkg/maputil/example_maputil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package maputil_test

import (
"fmt"

"github.com/Vonage/gosrvlib/pkg/maputil"
)

func ExampleFilter() {
m := map[int]string{0: "Hello", 1: "World"}

filterFn := func(_ int, v string) bool { return v == "World" }

s2 := maputil.Filter(m, filterFn)

fmt.Println(s2)

// Output:
// map[1:World]
}

func ExampleMap() {
m := map[int]string{0: "Hello", 1: "World"}

mapFn := func(k int, v string) (string, int) { return "_" + v, k + 1 }

s2 := maputil.Map(m, mapFn)

fmt.Println(s2)

// Output:
// map[_Hello:1 _World:2]
}

func ExampleReduce() {
m := map[int]int{0: 2, 1: 3, 2: 5, 3: 7, 4: 11}
init := 97
reduceFn := func(k, v, r int) int { return k + v + r }

r := maputil.Reduce(m, init, reduceFn)

fmt.Println(r)

// Output:
// 135
}

func ExampleInvert() {
m := map[int]int{1: 10, 2: 20}

s2 := maputil.Invert(m)

fmt.Println(s2)

// Output:
// map[10:1 20:2]
}
53 changes: 53 additions & 0 deletions pkg/maputil/maputil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Package maputil provides a collection of map functions.
package maputil

// Filter returns a new map containing
// only the elements in the input map m for which the specified function f is true.
func Filter[M ~map[K]V, K comparable, V any](m M, f func(K, V) bool) M {
r := make(M, len(m))

for k, v := range m {
if f(k, v) {
r[k] = v
}
}

return r
}

// Map returns a new map that contains
// each of the elements of the input map m mutated by the specified function.
func Map[M ~map[K]V, K, J comparable, V, U any](m M, f func(K, V) (J, U)) map[J]U {
r := make(map[J]U, len(m))

for k, v := range m {
j, u := f(k, v)
r[j] = u
}

return r
}

// Reduce applies the reducing function f
// to each element of the input map m, and returns the value of the last call to f.
// The first parameter of the reducing function f is initialized with init.
func Reduce[M ~map[K]V, K comparable, V, U any](m M, init U, f func(K, V, U) U) U {
r := init

for k, v := range m {
r = f(k, v, r)
}

return r
}

// Invert returns a new map were keys and values are swapped.
func Invert[M ~map[K]V, K, V comparable](m M) map[V]K {
r := make(map[V]K, len(m))

for k, v := range m {
r[v] = k
}

return r
}
56 changes: 56 additions & 0 deletions pkg/maputil/maputil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package maputil

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestFilter(t *testing.T) {
t.Parallel()

m := map[int]string{0: "Hello", 1: "World"}
filterFn := func(_ int, v string) bool { return v == "World" }

got := Filter(m, filterFn)

require.Len(t, got, 1)
require.Equal(t, "World", m[1])
}

func TestMap(t *testing.T) {
t.Parallel()

m := map[int]string{0: "Hello", 1: "World"}
mapFn := func(k int, v string) (string, int) { return "_" + v, k + 1 }

got := Map(m, mapFn)

require.Len(t, got, 2)
require.Equal(t, 1, got["_Hello"])
require.Equal(t, 2, got["_World"])
}

func TestReduce(t *testing.T) {
t.Parallel()

m := map[int]int{0: 2, 1: 3, 2: 5, 3: 7, 4: 11}
init := 97
reduceFn := func(k, v, r int) int { return k + v + r }

got := Reduce(m, init, reduceFn)

require.Equal(t, 135, got)
}

func TestInvert(t *testing.T) {
t.Parallel()

m := map[int]int{1: 10, 2: 20}

got := Invert(m)

require.Len(t, got, 2)
require.Equal(t, 1, got[10])
require.Equal(t, 2, got[20])
}
47 changes: 47 additions & 0 deletions pkg/sliceutil/example_sliceutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package sliceutil_test

import (
"fmt"

"github.com/Vonage/gosrvlib/pkg/sliceutil"
)

func ExampleFilter() {
s := []string{"Hello", "World", "Extra"}

filterFn := func(_ int, v string) bool { return v == "World" }

s2 := sliceutil.Filter(s, filterFn)

fmt.Println(s2)

// Output:
// [World]
}

func ExampleMap() {
s := []string{"Hello", "World", "Extra"}

mapFn := func(k int, v string) int { return k + len(v) }

s2 := sliceutil.Map(s, mapFn)

fmt.Println(s2)

// Output:
// [5 6 7]
}

func ExampleReduce() {
s := []int{2, 3, 5, 7, 11}

init := 97
reduceFn := func(k, v, r int) int { return k + v + r }

r := sliceutil.Reduce(s, init, reduceFn)

fmt.Println(r)

// Output:
// 135
}
41 changes: 41 additions & 0 deletions pkg/sliceutil/sliceutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Package sliceutil provides a collection of slice functions.
package sliceutil

// Filter returns a new slice containing
// only the elements in the input slice s for which the specified function f is true.
func Filter[S ~[]E, E any](s S, f func(int, E) bool) S {
r := make(S, 0)

for k, v := range s {
if f(k, v) {
r = append(r, v)
}
}

return r
}

// Map returns a new slice that contains
// each of the elements of the input slice s mutated by the specified function.
func Map[S ~[]E, E any, U any](s S, f func(int, E) U) []U {
r := make([]U, len(s))

for k, v := range s {
r[k] = f(k, v)
}
nicolaasuni-vonage marked this conversation as resolved.
Show resolved Hide resolved

return r
}

// Reduce applies the reducing function f
// to each element of the input slice s, and returns the value of the last call to f.
// The first parameter of the reducing function f is initialized with init.
func Reduce[S ~[]E, E any, U any](s S, init U, f func(int, E, U) U) U {
r := init

for k, v := range s {
r = f(k, v, r)
}

return r
}
41 changes: 41 additions & 0 deletions pkg/sliceutil/sliceutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package sliceutil

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestFilter(t *testing.T) {
t.Parallel()

s := []string{"Hello", "World", "Extra"}
filterFn := func(_ int, v string) bool { return v == "World" }

got := Filter(s, filterFn)

require.ElementsMatch(t, []string{"World"}, got)
}

func TestMap(t *testing.T) {
t.Parallel()

s := []string{"Hello", "World", "Extra"}
mapFn := func(k int, v string) int { return k + len(v) }

got := Map(s, mapFn)

require.ElementsMatch(t, []int{5, 6, 7}, got)
}

func TestReduce(t *testing.T) {
t.Parallel()

s := []int{2, 3, 5, 7, 11}
init := 97
reduceFn := func(k, v, r int) int { return k + v + r }

got := Reduce(s, init, reduceFn)

require.Equal(t, 135, got)
}
13 changes: 13 additions & 0 deletions pkg/threadsafe/tsmap/example_tsmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,16 @@ func ExampleReduce() {
// Output:
// 135
}

func ExampleInvert() {
mux := &sync.RWMutex{}

m := map[int]int{1: 10, 2: 20}

s2 := tsmap.Invert(mux, m)

fmt.Println(s2)

// Output:
// map[10:1 20:2]
}
32 changes: 10 additions & 22 deletions pkg/threadsafe/tsmap/tsmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package tsmap

import (
"github.com/Vonage/gosrvlib/pkg/maputil"
"github.com/Vonage/gosrvlib/pkg/threadsafe"
)

Expand Down Expand Up @@ -35,15 +36,7 @@ func Filter[M ~map[K]V, K comparable, V any](mux threadsafe.RLocker, m M, f func
mux.RLock()
defer mux.RUnlock()

r := make(M, len(m))

for k, v := range m {
if f(k, v) {
r[k] = v
}
}

return r
return maputil.Filter(m, f)
}

// Map is a thread-safe function that returns a new map that contains
Expand All @@ -53,14 +46,7 @@ func Map[M ~map[K]V, K, J comparable, V, U any](mux threadsafe.RLocker, m M, f f
mux.RLock()
defer mux.RUnlock()

r := make(map[J]U, len(m))

for k, v := range m {
j, u := f(k, v)
r[j] = u
}

return r
return maputil.Map(m, f)
}

// Reduce is a thread-safe function that applies the reducing function f
Expand All @@ -70,11 +56,13 @@ func Reduce[M ~map[K]V, K comparable, V, U any](mux threadsafe.RLocker, m M, ini
mux.RLock()
defer mux.RUnlock()

r := init
return maputil.Reduce(m, init, f)
}

for k, v := range m {
r = f(k, v, r)
}
// Invert is a thread-safe function that returns a new map were keys and values are swapped.
func Invert[M ~map[K]V, K, V comparable](mux threadsafe.RLocker, m M) map[V]K {
mux.RLock()
defer mux.RUnlock()

return r
return maputil.Invert(m)
}
Loading