Browse Source

internal/sliceutil: add utilities to map values

Functional programming for the win! Add a utility function to map the
values of a slice, along with a curried variant, to tide us over until
equivalent functionality gets added to the standard library
(https://go.dev/issue/61898)

Signed-off-by: Cory Snider <csnider@mirantis.com>
Cory Snider 1 year ago
parent
commit
e245fb76de
2 changed files with 67 additions and 0 deletions
  1. 18 0
      internal/sliceutil/sliceutil.go
  2. 49 0
      internal/sliceutil/sliceutil_test.go

+ 18 - 0
internal/sliceutil/sliceutil.go

@@ -11,3 +11,21 @@ func Dedup[T comparable](slice []T) []T {
 	}
 	return out
 }
+
+func Map[S ~[]In, In, Out any](s S, fn func(In) Out) []Out {
+	res := make([]Out, len(s))
+	for i, v := range s {
+		res[i] = fn(v)
+	}
+	return res
+}
+
+func Mapper[In, Out any](fn func(In) Out) func([]In) []Out {
+	return func(s []In) []Out {
+		res := make([]Out, len(s))
+		for i, v := range s {
+			res[i] = fn(v)
+		}
+		return res
+	}
+}

+ 49 - 0
internal/sliceutil/sliceutil_test.go

@@ -0,0 +1,49 @@
+package sliceutil_test
+
+import (
+	"net/netip"
+	"strconv"
+	"testing"
+
+	"github.com/docker/docker/internal/sliceutil"
+)
+
+func TestMap(t *testing.T) {
+	s := []int{1, 2, 3}
+	m := sliceutil.Map(s, func(i int) int { return i * 2 })
+	if len(m) != len(s) {
+		t.Fatalf("expected len %d, got %d", len(s), len(m))
+	}
+	for i, v := range m {
+		if expected := s[i] * 2; v != expected {
+			t.Fatalf("expected %d, got %d", expected, v)
+		}
+	}
+}
+
+func TestMap_TypeConvert(t *testing.T) {
+	s := []int{1, 2, 3}
+	m := sliceutil.Map(s, func(i int) string { return strconv.Itoa(i) })
+	if len(m) != len(s) {
+		t.Fatalf("expected len %d, got %d", len(s), len(m))
+	}
+	for i, v := range m {
+		if expected := strconv.Itoa(s[i]); v != expected {
+			t.Fatalf("expected %s, got %s", expected, v)
+		}
+	}
+}
+
+func TestMapper(t *testing.T) {
+	s := []string{"1.2.3.4", "fe80::1"}
+	mapper := sliceutil.Mapper(netip.MustParseAddr)
+	m := mapper(s)
+	if len(m) != len(s) {
+		t.Fatalf("expected len %d, got %d", len(s), len(m))
+	}
+	for i, v := range m {
+		if expected := netip.MustParseAddr(s[i]); v != expected {
+			t.Fatalf("expected %s, got %s", expected, v)
+		}
+	}
+}