diff options
author | Marc Pervaz Boocha <mboocha@sudomsg.com> | 2025-08-02 20:55:11 +0530 |
---|---|---|
committer | Marc Pervaz Boocha <mboocha@sudomsg.com> | 2025-08-02 20:55:11 +0530 |
commit | ce6cf13c2d67c3368251d1eea5593198f5021330 (patch) | |
tree | d4c2347fd45fce395bf22a30e423697494d4284f /generic | |
download | kit-f56c6730f284513e728f9337d1c92f91938bea46.tar kit-f56c6730f284513e728f9337d1c92f91938bea46.tar.gz kit-f56c6730f284513e728f9337d1c92f91938bea46.tar.bz2 kit-f56c6730f284513e728f9337d1c92f91938bea46.tar.lz kit-f56c6730f284513e728f9337d1c92f91938bea46.tar.xz kit-f56c6730f284513e728f9337d1c92f91938bea46.tar.zst kit-f56c6730f284513e728f9337d1c92f91938bea46.zip |
Initial Commitv0.1.0
Diffstat (limited to 'generic')
-rw-r--r-- | generic/generic.go | 106 | ||||
-rw-r--r-- | generic/generic_test.go | 149 |
2 files changed, 255 insertions, 0 deletions
diff --git a/generic/generic.go b/generic/generic.go new file mode 100644 index 0000000..8ac3c51 --- /dev/null +++ b/generic/generic.go @@ -0,0 +1,106 @@ +// Package generic provides common generic utility functions and types. +// +// It includes zero value helpers, pointer helpers, iteration helpers for map-like sequences, +// and a simple generic Set implementation. +package generic + +import ( + "iter" + "maps" +) + +// Package generic provides common generic utility functions and types. +// +// It includes zero value helpers, pointer helpers, iteration helpers for map-like sequences, +// and a simple generic Set implementation. +func Zero[T any]() T { + var v T + return v +} + +// IsZero reports whether the given value is the zero value of its type. +// +// T must be comparable (support == operator). +// +// Example: +// +// generic.IsZero(0) // true +// generic.IsZero("a") // false +func IsZero[T comparable](v T) bool { + return v == Zero[T]() +} + +// Ptr returns a pointer to the given value. +// +// This is a concise helper to get the address of a value inline. +// +// Example: +// +// p := generic.Ptr(42) // *int with value 42 +func Ptr[T any](v T) *T { + return &v +} + +// Keys returns an iterator (Seq) over the keys of the input map-like sequence. +// +// Utilizes iter.Seq2[K,V] as input and yields keys K. +// +// Usage example (assuming iter.Seq is a func type yielding values): +// +// forKeys := generic.Keys(yourMapSeq) +// forKeys(func(k K) bool { +// fmt.Println(k) +// return true +// }) +func Keys[K comparable, V any](m iter.Seq2[K, V]) iter.Seq[K] { + return func(yield func(K) bool) { + for k := range m { + if !yield(k) { + return + } + } + } +} + +// Value returns an iterator over the values of the input map-like sequence. +// +// Usage is analogous to Keys() but yields values of type V. +func Value[K comparable, V any](m iter.Seq2[K, V]) iter.Seq[V] { + return func(yield func(V) bool) { + for _, v := range m { + if !yield(v) { + return + } + } + } +} + +// Set represents a generic set of comparable items. +// +// It is a thin wrapper around a map[T]struct{} for set semantics. +type Set[T comparable] map[T]struct{} + +func NewSet[T comparable]() Set[T] { + return make(Set[T]) +} + +// All returns an iterator (Seq) over all elements in the Set. +func (s Set[T]) All() iter.Seq[T] { + return maps.Keys(s) +} + +// Add inserts the value v into the Set. +func (s Set[T]) Add(v T) { + s[v] = struct{}{} +} + +// Del removes the value v from the Set. +func (s Set[T]) Del(v T) { + delete(s, v) +} + +// Has reports whether the value v is present in the Set. +func (s Set[T]) Has(v T) bool { + _, ok := s[v] + return ok +} diff --git a/generic/generic_test.go b/generic/generic_test.go new file mode 100644 index 0000000..953f2ac --- /dev/null +++ b/generic/generic_test.go @@ -0,0 +1,149 @@ +package generic + +import ( + "maps" + "slices" + "testing" +) + +type X struct{} + +func TestZero(t *testing.T) { + if Zero[int]() != 0 { + t.Errorf("Zero[int]() != 0") + } + if Zero[string]() != "" { + t.Errorf(`Zero[string]() != ""`) + } + if Zero[bool]() != false { + t.Errorf("Zero[bool]() != false") + } + if Zero[*X]() != nil { + t.Errorf("Zero[*X]() != nil") + } +} + +func TestIsZero(t *testing.T) { + tests := []struct { + name string + val any + want bool + }{ + { + name: "int zero", + val: 0, + want: true, + }, + { + "int non-zero", + 1, + false, + }, + { + "string zero", + "", + true, + }, + { + "string non-zero", + "x", + false, + }, + { + "nil pointer", + (*X)(nil), + true, + }, + { + "non-nil pointer", + Ptr(X{}), + false, + }, + } + + for _, tt := range tests { + switch v := tt.val.(type) { + case int: + got := IsZero(v) + if got != tt.want { + t.Errorf("%s: got %v, want %v", tt.name, got, tt.want) + } + case string: + got := IsZero(v) + if got != tt.want { + t.Errorf("%s: got %v, want %v", tt.name, got, tt.want) + } + case *X: + got := IsZero(v) + if got != tt.want { + t.Errorf("%s: got %v, want %v", tt.name, got, tt.want) + } + } + } +} + +func TestPtr(t *testing.T) { + v := 42 + p := Ptr(v) + if p == nil || *p != v { + t.Errorf("Ptr(42) = %v, want pointer to 42", p) + } +} + +func TestKeys(t *testing.T) { + m := map[string]int{"a": 1, "b": 2, "c": 3} + seq := Keys(maps.All(m)) + keys := slices.Collect(seq) + want := slices.Collect(maps.Keys(m)) + + slices.Sort(keys) + slices.Sort(want) + if !slices.Equal(keys, want) { + t.Errorf("Keys() = %v, want %v", keys, want) + } +} + +func TestValue(t *testing.T) { + m := map[string]int{"a": 1, "b": 2, "c": 3} + seq := Value(maps.All(m)) + values := slices.Collect(seq) + want := slices.Collect(maps.Values(m)) + + // unordered compare + slices.Sort(values) + slices.Sort(want) + if !slices.Equal(values, want) { + t.Errorf("Values() = %v, want %v", values, want) + } +} + +func TestSet_Add_Has_Del(t *testing.T) { + s := NewSet[int]() + if s.Has(10) { + t.Errorf("Set should not contain 10 initially") + } + s.Add(10) + if !s.Has(10) { + t.Errorf("Set should contain 10 after Add") + } + s.Del(10) + if s.Has(10) { + t.Errorf("Set should not contain 10 after Del") + } +} + +func TestSet_All(t *testing.T) { + s := NewSet[string]() + s.Add("x") + s.Add("y") + s.Add("z") + + got := slices.Collect(s.All()) + want := []string{"x", "y", "z"} + + slices.Sort(got) + slices.Sort(want) + if !slices.Equal(got, want) { + t.Errorf("Set.All() = %v, want %v", got, want) + } +} |