feat(set): initial work
This commit is contained in:
parent
2e6c36c8f7
commit
a57bf0d1c4
|
@ -0,0 +1 @@
|
|||
/.idea/
|
|
@ -0,0 +1,184 @@
|
|||
package goset
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Set struct {
|
||||
m map[any]any
|
||||
}
|
||||
|
||||
type StrictSet struct {
|
||||
m map[any]any
|
||||
typ reflect.Type
|
||||
}
|
||||
|
||||
var ErrMismatchType = errors.New("must have same type for all the members")
|
||||
|
||||
func NewSet(v ...any) *Set {
|
||||
return NewSetSlice(v)
|
||||
}
|
||||
|
||||
func NewSetSlice(v []any) *Set {
|
||||
mapper := make(map[any]any)
|
||||
for _, item := range v {
|
||||
mapper[item] = nil
|
||||
}
|
||||
|
||||
m := &Set{
|
||||
m: mapper,
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func (s *Set) Add(v any) {
|
||||
mapper := s.m
|
||||
mapper[v] = nil
|
||||
s.m = mapper
|
||||
}
|
||||
|
||||
func (s *Set) Remove(v any) {
|
||||
mapper := s.m
|
||||
delete(mapper, v)
|
||||
s.m = mapper
|
||||
}
|
||||
|
||||
func (s *Set) Has(v any) bool {
|
||||
_, ok := s.m[v]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s *Set) Len() int {
|
||||
return len(s.m)
|
||||
}
|
||||
|
||||
func NewStrictSetErr(v ...any) (*StrictSet, error) {
|
||||
return NewStrictSetSliceErr(v)
|
||||
}
|
||||
|
||||
func NewStrictSetSliceErr(v []any) (set *StrictSet, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
set = nil
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
set = NewStrictSetSlice(v)
|
||||
return
|
||||
}
|
||||
|
||||
func NewStrictSet(v ...any) *StrictSet {
|
||||
return NewStrictSetSlice(v)
|
||||
}
|
||||
|
||||
func NewStrictSetSlice(v []any) *StrictSet {
|
||||
if len(v) > 0 {
|
||||
mapper := make(map[any]any)
|
||||
typ := reflect.TypeOf(v[0])
|
||||
|
||||
for _, item := range v {
|
||||
if reflect.TypeOf(item) != typ {
|
||||
panic(ErrMismatchType)
|
||||
}
|
||||
|
||||
mapper[item] = nil
|
||||
}
|
||||
|
||||
return &StrictSet{
|
||||
m: mapper,
|
||||
typ: typ,
|
||||
}
|
||||
}
|
||||
|
||||
return &StrictSet{}
|
||||
}
|
||||
|
||||
func (s *StrictSet) AddErr(v any) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
s.Add(v)
|
||||
return
|
||||
}
|
||||
|
||||
func (s *StrictSet) Add(v any) {
|
||||
if s.typ == nil {
|
||||
s.typ = reflect.TypeOf(v)
|
||||
s.m = map[any]any{v: nil}
|
||||
return
|
||||
}
|
||||
|
||||
if reflect.TypeOf(v) != s.typ {
|
||||
panic(ErrMismatchType)
|
||||
}
|
||||
|
||||
mapper := s.m
|
||||
|
||||
mapper[v] = nil
|
||||
|
||||
s.m = mapper
|
||||
}
|
||||
|
||||
func (s *StrictSet) Remove(v any) {
|
||||
if _, ok := s.m[v]; ok {
|
||||
mapper := s.m
|
||||
|
||||
delete(mapper, v)
|
||||
|
||||
s.m = mapper
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StrictSet) Has(v any) bool {
|
||||
_, ok := s.m[v]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (s *StrictSet) Len() int {
|
||||
return len(s.m)
|
||||
}
|
||||
|
||||
func (s *StrictSet) Distinct(v any) (int, error) {
|
||||
val := reflect.ValueOf(v)
|
||||
if val.IsNil() {
|
||||
return 0, errors.New("the output parameter is nil")
|
||||
}
|
||||
|
||||
if val.Kind() == reflect.Pointer {
|
||||
val = val.Elem()
|
||||
if val.Kind() != reflect.Slice {
|
||||
return 0, fmt.Errorf("unsupported type pointer of %v", val.Type())
|
||||
}
|
||||
if s.typ != val.Type().Elem() {
|
||||
return 0, fmt.Errorf("invalid output parameter type %v", val.Type().Elem())
|
||||
}
|
||||
|
||||
for item := range s.m {
|
||||
val.Set(reflect.Append(val, reflect.ValueOf(item)))
|
||||
}
|
||||
return val.Len(), nil
|
||||
} else if val.Kind() == reflect.Slice {
|
||||
if len(s.m) > val.Len() {
|
||||
return 0, errors.New("insufficient length of the output parameter")
|
||||
}
|
||||
if s.typ != val.Type().Elem() {
|
||||
return 0, fmt.Errorf("invalid output parameter type %v", val.Type())
|
||||
}
|
||||
|
||||
ctr := 0
|
||||
for item := range s.m {
|
||||
val.Index(ctr).Set(reflect.ValueOf(item))
|
||||
ctr++
|
||||
}
|
||||
return ctr, nil
|
||||
} else {
|
||||
return 0, fmt.Errorf("invalid type %v", val.Type())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package goset
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestInitial(t *testing.T) {
|
||||
NewSet("hello", "world", 1, 1.5, "world")
|
||||
}
|
||||
|
||||
func TestDua(t *testing.T) {
|
||||
s := NewStrictSet("hello", "world", "go", "further")
|
||||
s.Remove("hello")
|
||||
}
|
||||
|
||||
func TestDistinct(t *testing.T) {
|
||||
var (
|
||||
out []string
|
||||
err error
|
||||
len int
|
||||
)
|
||||
s := NewStrictSet("hello", "world", "go", "further")
|
||||
|
||||
len, err = s.Distinct(&out)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error %v", err)
|
||||
}
|
||||
|
||||
if len != 4 {
|
||||
t.Fatalf("unexpected length %v", len)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue