From 096a02691691686f86203c8f58d3458a2aa3d1d3 Mon Sep 17 00:00:00 2001 From: Yi-Ting Shih Date: Thu, 6 Nov 2025 04:32:40 +0800 Subject: [PATCH] Init: w9 code done --- Makefile | 16 ++++ go.mod | 3 + intset.go | 116 +++++++++++++++++++++++ intset_test.go | 247 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 382 insertions(+) create mode 100644 Makefile create mode 100644 go.mod create mode 100644 intset.go create mode 100644 intset_test.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bcd1473 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +.PHONY: all watch clean + +SOURCE := $(shell find docs/ -type f -name '*.typ') +TARGET := docs/main.pdf +TYPST_ARGS += --root . + +all: $(TARGET) + +docs/main.pdf: docs/main.typ $(SOURCE) + typst compile $(TYPST_ARGS) $< + +watch: + typst watch --root . docs/main.typ + +clean: + -rm docs/main.pdf diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cab6bae --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module intset + +go 1.25.2 diff --git a/intset.go b/intset.go new file mode 100644 index 0000000..f85b40e --- /dev/null +++ b/intset.go @@ -0,0 +1,116 @@ +package intset + +import ( + "bytes" + "fmt" + "math/bits" + "slices" +) + +type IntSet struct { + words []uint64 +} + +func (s *IntSet) Has(x int) bool { + word, bit := x/64, uint(x%64) + return word < len(s.words) && s.words[word]&uint64(1<= len(s.words) { + s.words = append(s.words, 0) + } + s.words[word] |= uint64(1 << bit) +} + +func (s *IntSet) UnionWith(t *IntSet) { + for i, tword := range t.words { + if i < len(s.words) { + s.words[i] |= tword + } else { + s.words = append(s.words, tword) + } + } +} + +func (s *IntSet) String() string { + var buf bytes.Buffer + buf.WriteByte('{') + for i, word := range s.words { + if word == 0 { + continue + } + for j := 0; j < 64; j++ { + if word&uint64(1< len("{") { + buf.WriteByte(' ') + } + fmt.Fprintf(&buf, "%d", 64*i+j) + } + } + } + buf.WriteByte('}') + return buf.String() +} + +func (s *IntSet) Len() int { + res := 0 + for _, word := range s.words { + res += bits.OnesCount64(word) + } + return res +} + +func (s *IntSet) Remove(x int) { + word, bit := x/64, uint(x%64) + if word < len(s.words) { + s.words[word] &= ^(1 << bit) + } +} + +func (s *IntSet) Clear() { + s.words = []uint64{} +} + +func (s *IntSet) Copy() *IntSet { + return &IntSet{ + words: slices.Clone(s.words), + } +} + +func (s *IntSet) AddAll(xs ...int) { + for _, x := range xs { + s.Add(x) + } +} + +func (s *IntSet) IntersectWith(o *IntSet) { + for word := range s.words { + if word >= len(o.words) { + return + } + s.words[word] &= o.words[word] + } +} + +func (s *IntSet) DifferenceWith(o *IntSet) { + for word := range s.words { + if word >= len(o.words) { + return + } + s.words[word] &= ^o.words[word] + } +} + +func (s *IntSet) SymmetricDifference(o *IntSet) { + for word := range s.words { + if word >= len(o.words) { + return + } + s.words[word] ^= o.words[word] + } + for i := len(s.words); i < len(o.words); i++ { + s.words = append(s.words, o.words[i]) + } +} diff --git a/intset_test.go b/intset_test.go new file mode 100644 index 0000000..c7d4e83 --- /dev/null +++ b/intset_test.go @@ -0,0 +1,247 @@ +package intset + +import ( + "fmt" + "testing" +) + +func Example_one() { + //!+main + var x, y IntSet + x.Add(1) + x.Add(144) + x.Add(9) + fmt.Println(x.String()) // "{1 9 144}" + + y.Add(9) + y.Add(42) + fmt.Println(y.String()) // "{9 42}" + + x.UnionWith(&y) + fmt.Println(x.String()) // "{1 9 42 144}" + + fmt.Println(x.Has(9), x.Has(123)) // "true false" + //!-main + + // Output: + // {1 9 144} + // {9 42} + // {1 9 42 144} + // true false +} + +func Example_two() { + var x IntSet + x.Add(1) + x.Add(144) + x.Add(9) + x.Add(42) + + //!+note + fmt.Println(&x) // "{1 9 42 144}" + fmt.Println(x.String()) // "{1 9 42 144}" + fmt.Println(x) // "{[4398046511618 0 65536]}" + //!-note + + // Output: + // {1 9 42 144} + // {1 9 42 144} + // {[4398046511618 0 65536]} +} + +func TestLen(t *testing.T) { + var tcs = []struct { + words []int + expects int + }{ + {[]int{}, 0}, + {[]int{1, 2, 101}, 3}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8, 1024}, 9}, + } + for _, tc := range tcs { + var s IntSet + for _, w := range tc.words { + s.Add(w) + } + if s.Len() != tc.expects { + t.Errorf("Len of %v, Actual: %d, Expects %d", tc.words, s.Len(), tc.expects) + } + } +} + +func TestRemove(t *testing.T) { + var tcs = []struct { + words []int + remove int + expects string + }{ + {[]int{}, 1, "{}"}, + {[]int{1, 2, 3}, 2, "{1 3}"}, + } + + for _, tc := range tcs { + var s IntSet + for _, w := range tc.words { + s.Add(w) + } + + s.Remove(tc.remove) + + if s.String() != tc.expects { + t.Errorf("Remove %d from %v, Actual = %s, Expects %s", tc.remove, tc.words, s.String(), tc.expects) + } + + } +} + +func TestClear(t *testing.T) { + var tcs = []IntSet{ + IntSet{}, + IntSet{words: []uint64{1, 2, 3}}, + } + + for _, tc := range tcs { + tc.Clear() + if tc.Len() != 0 { + t.Errorf("Clear failed. IntSet: %q", tc) + } + } +} + +func TestCopy(t *testing.T) { + var tcs = []IntSet{ + IntSet{}, + IntSet{words: []uint64{1, 2, 3, 4, 5, 6, 7, 8}}, + IntSet{words: []uint64{1, 2, 1, 2, 1, 2, 1, 2}}, + } + + for _, tc := range tcs { + actual := tc.Copy() + for i := 0; i < len(tc.words); i++ { + if actual.words[i] != tc.words[i] { + t.Errorf("Copy: %v, Actual: %v", tc, actual) + } + } + } +} + +func TestAddAll(t *testing.T) { + var tcs = []struct { + ints []int + values []int + expects string + }{ + {[]int{}, []int{1, 2, 3}, "{1 2 3}"}, + {[]int{1, 2, 3}, []int{}, "{1 2 3}"}, + {[]int{1, 2, 3}, []int{2}, "{1 2 3}"}, + {[]int{1, 2, 3, 4, 6, 7, 8}, []int{1024}, "{1 2 3 4 6 7 8 1024}"}, + } + + for _, tc := range tcs { + s := &IntSet{} + for _, i := range tc.ints { + s.Add(i) + } + + s.AddAll(tc.values...) + + if s.String() != tc.expects { + t.Errorf("IntSet: %v AddAll %v, Expects: %s, Actual: %s", tc.ints, tc.values, tc.expects, s.String()) + } + + } +} + +func TestIntersectWith(t *testing.T) { + var tcs = []struct { + s []int + t []int + expects string + }{ + {[]int{1}, []int{2, 3, 4}, "{}"}, + {[]int{1, 2, 3}, []int{2, 3, 4}, "{2 3}"}, + {[]int{1, 2, 3}, []int{2}, "{2}"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8}, []int{8, 2}, "{2 8}"}, + } + + for _, tc := range tcs { + s := &IntSet{} + o := &IntSet{} + for _, i := range tc.s { + s.Add(i) + } + for _, i := range tc.t { + o.Add(i) + } + + s.IntersectWith(o) + + if s.String() != tc.expects { + t.Errorf("%v IntersectWith %v, Expects: %s, Actual: %s", tc.s, tc.t, tc.expects, s.String()) + } + + } +} + +func TestDifferenceWith(t *testing.T) { + var tcs = []struct { + s []int + t []int + expects string + }{ + {[]int{1}, []int{2, 3, 4}, "{1}"}, + {[]int{1, 2, 3}, []int{2, 3, 4}, "{1}"}, + {[]int{1, 2, 3}, []int{1, 2, 3}, "{}"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8}, []int{8, 2}, "{1 3 4 5 6 7}"}, + } + + for _, tc := range tcs { + s := &IntSet{} + o := &IntSet{} + for _, i := range tc.s { + s.Add(i) + } + for _, i := range tc.t { + o.Add(i) + } + + s.DifferenceWith(o) + + if s.String() != tc.expects { + t.Errorf("%v DifferenceWith %v, Expects: %s, Actual: %s", tc.s, tc.t, tc.expects, s.String()) + } + + } +} + +func TestSymmetricDifference(t *testing.T) { + var tcs = []struct { + s []int + t []int + expects string + }{ + {[]int{1}, []int{2, 3, 4}, "{1 2 3 4}"}, + {[]int{1, 2, 3}, []int{1, 2, 3}, "{}"}, + {[]int{1, 2, 3}, []int{2}, "{1 3}"}, + {[]int{1, 2, 3}, []int{2, 3, 4}, "{1 4}"}, + {[]int{1, 2, 3, 4, 5, 6, 7, 8}, []int{8, 2, 9, 10}, "{1 3 4 5 6 7 9 10}"}, + } + + for _, tc := range tcs { + s := &IntSet{} + o := &IntSet{} + for _, i := range tc.s { + s.Add(i) + } + for _, i := range tc.t { + o.Add(i) + } + + s.SymmetricDifference(o) + + if s.String() != tc.expects { + t.Errorf("%v SymmetricDifference with %v, Expects: %s, Actual: %s", tc.s, tc.t, tc.expects, s.String()) + } + + } +}