diff --git a/containers/linked_hash_map/linked_hash_map.go b/containers/linked_hash_map/linked_hash_map.go new file mode 100644 index 0000000..67c0269 --- /dev/null +++ b/containers/linked_hash_map/linked_hash_map.go @@ -0,0 +1,177 @@ +// Copyright 2021. The GTL Authors. All rights reserved. +// https://github.com/modern-dev/gtl +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE file. + +package linked_hash_map + +import ( + "github.com/modern-dev/gtl" +) + +type ( + // LinkedHashMap TODO + LinkedHashMap[TKey comparable, TVal any] struct { + store map[TKey][]*node[TVal] + head, tail *node[TVal] + dupl bool + size int + } + + node[TVal any] struct { + val TVal + prev, next *node[TVal] + } +) + +// NewLinkedHashMap TODO +func NewLinkedHashMap[TKey comparable, TVal any](allowDuplicates bool) *LinkedHashMap[TKey, TVal] { + head, tail := &node[TVal]{}, &node[TVal]{} + head.next = tail + tail.prev = head + + return &LinkedHashMap[TKey, TVal]{ + make(map[TKey][]*node[TVal]), + head, + tail, + allowDuplicates, + 0, + } +} + +/* Capacity members */ + +// Empty checks if the container has no elements. +// Complexity — constant. +func (lhm *LinkedHashMap[TKey, TVal]) Empty() bool { + return lhm.Size() == 0 +} + +// Size returns the number of elements in the container. +// Complexity — constant. +func (lhm *LinkedHashMap[TKey, TVal]) Size() int { + return lhm.size +} + +/* Modifiers members */ + +// Clear erases all elements from the container. After this call, Size() returns zero. +// Complexity — constant. +func (lhm *LinkedHashMap[TKey, TVal]) Clear() { + lhm.head.next = lhm.tail + lhm.tail.prev = lhm.head + lhm.store = make(map[TKey][]*node[TVal]) + lhm.size = 0 +} + +// Insert inserts element into the container. +// Complexity — average case - O(1), worst case - O(size()). +func (lhm *LinkedHashMap[TKey, TVal]) Insert(key TKey, val TVal) bool { + if _, found := lhm.store[key]; found && !lhm.dupl { + return false + } + + newNode := &node[TVal]{ + val, + nil, + nil, + } + + lhm.store[key] = append(lhm.store[key], newNode) + lhm.size++ + + lhm.appendNode(newNode) + + return true +} + +// Assign assigns to the current element if the key already exists. +// Throws gtl.OutOfRange if the container does not have an element with the specified key. +// Complexity — constant. +func (lhm *LinkedHashMap[TKey, TVal]) Assign(key TKey, val TVal) { + lhm.getNode(key, 0).val = val +} + +// InsertOrAssign inserts an element or assigns to the current element if the key already exists. +// Returns true if the insertion took place and false if the assignment took place. +// Complexity — average case - O(1), worst case - O(Size()). +func (lhm *LinkedHashMap[TKey, TVal]) InsertOrAssign(key TKey, val TVal) bool { + if lhm.Contains(key) { + lhm.Assign(key, val) + + return false + } + + return lhm.Insert(key, val) +} + +// Erase removes all elements with the key equivalent to key. +// Complexity — average case - O(1), worst case - O(Size()). +func (lhm *LinkedHashMap[TKey, TVal]) Erase(key TKey) { + if _, found := lhm.store[key]; !found { + return + } + + for _, remNode := range lhm.store[key] { + lhm.removeNode(remNode) + } + + lhm.size -= len(lhm.store[key]) + + delete(lhm.store, key) +} + +/* Lookup members */ + +// At returns a reference to the mapped value of the element with key equivalent to key. +// If no such element exists, a panic of type gtl.OutOfRange is thrown. +// Complexity — constant. +func (lhm *LinkedHashMap[TKey, TVal]) At(key TKey) TVal { + return lhm.getNode(key, 0).val +} + +// Count returns the number of elements with key that compares equal to the specified argument key. +// Complexity — linear in the number of elements with key on average, worst case linear in the size of the container. +func (lhm *LinkedHashMap[TKey, TVal]) Count(key TKey) int { + items, found := lhm.store[key] + + if !found { + return 0 + } + + return len(items) +} + +// Contains checks if there is an element with key equivalent to key in the container. +// Complexity — constant. +func (lhm *LinkedHashMap[TKey, TVal]) Contains(key TKey) bool { + _, found := lhm.store[key] + + return found +} + +/* Private members */ + +func (lhm *LinkedHashMap[TKey, TVal]) appendNode(newNode *node[TVal]) { + next := lhm.head.next + + next.prev = newNode + newNode.next = next + lhm.head.next = newNode + newNode.prev = lhm.head +} + +func (lhm *LinkedHashMap[TKey, TVal]) removeNode(remNode *node[TVal]) { + prev, next := remNode.prev, remNode.next + + prev.next = next + next.prev = prev +} + +func (lhm *LinkedHashMap[TKey, TVal]) getNode(key TKey, idx int) *node[TVal] { + if items, found := lhm.store[key]; lhm.Empty() || !found || len(items) == 0 { + panic(gtl.OutOfRange) + } + + return lhm.store[key][idx] +} diff --git a/containers/linked_hash_map/linked_hash_map_test.go b/containers/linked_hash_map/linked_hash_map_test.go new file mode 100644 index 0000000..c99ebf6 --- /dev/null +++ b/containers/linked_hash_map/linked_hash_map_test.go @@ -0,0 +1,197 @@ +// Copyright 2021. The GTL Authors. All rights reserved. +// https://github.com/modern-dev/gtl +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE file. + +package linked_hash_map + +import ( + "math/rand" + "strconv" + "testing" +) + +func TestLinkedHashMapCapacityMembers(t *testing.T) { + lhm := NewLinkedHashMap[int, string](false) + lhmm := NewLinkedHashMap[int, string](true) + + if !lhm.Empty() { + t.Errorf("expected lhm not to be empty") + } + + if !lhmm.Empty() { + t.Errorf("expected lhmm not to be empty") + } + + for _, num := range []int{1, 2, 3, 4, 5, 5} { + lhm.Insert(num, strconv.Itoa(num)) + lhmm.Insert(num, strconv.Itoa(num)) + } + + if lhm.Size() != 5 { + t.Errorf("expected lhm to be the size of 5") + } + + if lhmm.Size() != 6 { + t.Errorf("expected lhmm to be the size of 6") + } + + lhm.Clear() + lhmm.Clear() + + if !lhm.Empty() { + t.Errorf("expected lhm not to be empty") + } + + if !lhmm.Empty() { + t.Errorf("expected lhmm not to be empty") + } +} + +func TestLinkedHashMapModifierAndLookupMembers(t *testing.T) { + cases := []struct { + name string + insert []int + expected []int + }{ + {"Example 1", []int{1, 2, 3, 4, 5}, []int{1, 3, 5}}, + {"Example 2", []int{-10, -50, 10, 50}, []int{-10, 10}}, + } + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + lhm := NewLinkedHashMap[int, string](false) + + for _, num := range tt.insert { + lhm.Insert(num, strconv.Itoa(num)) + } + + for _, num := range tt.expected { + if !lhm.Contains(num) { + t.Errorf("expected container to have value {%d}, but got false", num) + } + + if lhm.At(num) != strconv.Itoa(num) { + t.Errorf("expected key {%d} to have value {%s}", num, strconv.Itoa(num)) + } + } + }) + } +} + +func TestLinkedHashMapModifierAndLookupMembers2(t *testing.T) { + cases := []struct { + name string + insert []int + removed []int + }{ + {"Example 1", []int{1, 2, 3, 4, 5}, []int{1, 3, 5}}, + {"Example 2", []int{-10, -50, 10, 50}, []int{-10, 10}}, + } + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + lhm := NewLinkedHashMap[int, string](false) + + for _, num := range tt.insert { + lhm.Insert(num, strconv.Itoa(num)) + } + + for _, num := range tt.removed { + lhm.Erase(num) + } + + for _, num := range tt.removed { + if lhm.Contains(num) { + t.Errorf("expected container not to have value {%d}", num) + } + } + }) + } +} + +func TestLinkedHashMapModifierAndLookupMembers3(t *testing.T) { + cases := []struct { + name string + insert []int + modify [][]int + expected [][]int + }{ + { + "Example 1", + []int{1, 2, 3, 4, 5}, + [][]int{{1, 10}, {3, 30}, {5, 50}, {7, 70}}, + [][]int{{3, 30}, {7, 70}}, + }, { + "Example 2", + []int{-10, -50, 10, 50}, + [][]int{{-10, -20}, {10, 20}, {100, 200}}, + [][]int{{-10, -20}, {100, 200}}}, + } + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + lhm := NewLinkedHashMap[int, int](false) + + for _, num := range tt.insert { + lhm.Insert(num, num) + } + + for _, mod := range tt.modify { + lhm.InsertOrAssign(mod[0], mod[1]) + } + + for _, exp := range tt.expected { + if !lhm.Contains(exp[0]) { + t.Errorf("expected container to have the key of {%d}", exp[0]) + } + + if lhm.At(exp[0]) != exp[1] { + t.Errorf("expected container to have the key of {%d} be associated with {%d}, got {%d} instead", + exp[0], exp[1], lhm.At(exp[0])) + } + } + }) + } +} + +func TestLinkedHashMultiMapModifierAndLookupMembers(t *testing.T) { + cases := []struct { + name string + insert []int + expected [][]int + }{ + {"Example 1", []int{1, 2, 3, 4, 5, 3, 5, 5}, [][]int{{1, 1}, {3, 2}, {5, 3}, {7, 0}}}, + {"Example 2", []int{-10, -50, 10, 50, 10, 10, 1}, [][]int{{10, 3}, {1, 1}, {-20, 0}}}, + } + + for _, tt := range cases { + t.Run(tt.name, func(t *testing.T) { + lhm, rndInt := NewLinkedHashMap[int, string](true), rand.Intn(100) + + for _, num := range tt.insert { + lhm.Insert(num, strconv.Itoa(num)) + } + + for _, exp := range tt.expected { + if lhm.Count(exp[0]) != exp[1] { + t.Errorf("expected container to have {%d} key {%d} times, got {%d} instead", + exp[0], exp[1], lhm.Count(exp[0])) + } + } + + lhm.Clear() + + if !lhm.Empty() { + t.Errorf("expected container to be empty") + } + + defer func() { recover() }() + + lhm.Erase(rndInt) + lhm.At(rndInt) + + t.Errorf("expected to panic") + }) + } +} diff --git a/containers/unordered_set/unordered_set.go b/containers/unordered_set/unordered_set.go index 172df6b..9efcd8c 100644 --- a/containers/unordered_set/unordered_set.go +++ b/containers/unordered_set/unordered_set.go @@ -5,51 +5,66 @@ package unordered_set -// UnorderedSet is unordered unordered_set based on standard map -// It can contain comparable elements only -type UnorderedSet[T comparable] struct { - table map[T]bool -} +import ( + "github.com/modern-dev/gtl/containers/linked_hash_map" +) + +type ( + // UnorderedSet is unordered set based on linked_hash_map.LinkedHashMap. + // It can contain comparable elements only. + UnorderedSet[T comparable] struct { + lhm *linked_hash_map.LinkedHashMap[T, interface{}] + } +) +// NewUnorderedSet TODO func NewUnorderedSet[T comparable]() *UnorderedSet[T] { return &UnorderedSet[T]{ - make(map[T]bool), + linked_hash_map.NewLinkedHashMap[T, interface{}](false), } } -// Size returns the number of elements in the container. -// Complexity - O(1). -func (s *UnorderedSet[T]) Size() int { - return len(s.table) -} +/* Capacity members */ -// Empty checks if there are elements in Set. -// Complexity - O(1). -// Returns true if the unordered_set is empty, false otherwise. -func (s *UnorderedSet[T]) Empty() bool { - return s.Size() == 0 +// Empty checks if there are elements in UnorderedSet. +// Complexity — constant. +// Returns true if the UnorderedSet is empty, false otherwise. +func (us *UnorderedSet[T]) Empty() bool { + return us.lhm.Empty() } -// Insert inserts element into Set. -// Complexity - O(1). -func (s *UnorderedSet[T]) Insert(item T) { - s.table[item] = true +// Size returns the number of elements in the container. +// Complexity — constant. +func (us *UnorderedSet[T]) Size() int { + return us.lhm.Size() } -// Contains checks if Set contains given element. -// Complexity - O(1). -// returns true if Set includes the element, false otherwise. -func (s *UnorderedSet[T]) Contains(item T) bool { - _, exists := s.table[item] +/* Modifiers members */ - return exists +// Clear erases all elements from the container. After this call, Size() returns zero. +// Complexity — linear in the size of the container. +func (us *UnorderedSet[T]) Clear() { + us.lhm.Clear() +} + +// Insert inserts element into UnorderedSet. +// Complexity — average case - O(1), worst case O(Size()). +func (us *UnorderedSet[T]) Insert(item T) { + us.lhm.Insert(item, nil) } // Erase deletes the element from unordered_set if it contains an element // does nothing otherwise. -// Complexity - O(1). -func (s *UnorderedSet[T]) Erase(item T) { - if s.Contains(item) { - delete(s.table, item) - } +// Complexity — constant. +func (us *UnorderedSet[T]) Erase(item T) { + us.lhm.Erase(item) +} + +/* Lookup members */ + +// Contains checks if UnorderedSet contains given element. +// Complexity — constant. +// Returns true if UnorderedSet includes the element, false otherwise. +func (us *UnorderedSet[T]) Contains(item T) bool { + return us.lhm.Contains(item) } diff --git a/containers/unordered_set/unordered_set_test.go b/containers/unordered_set/unordered_set_test.go index 971b03d..973398a 100644 --- a/containers/unordered_set/unordered_set_test.go +++ b/containers/unordered_set/unordered_set_test.go @@ -11,7 +11,7 @@ import ( const addsCount = 3000 -func TestNewSet(t *testing.T) { +func TestNewUnorderedSet(t *testing.T) { s := NewUnorderedSet[int]() checkSize(s, 0, t) @@ -21,29 +21,29 @@ func TestNewSet(t *testing.T) { func TestInsert(t *testing.T) { s := NewUnorderedSet[int]() - checkSet[int](s, 0, true, t) + checkSet(s, 0, true, t) for i := 0; i < addsCount; i++ { s.Insert(i) - checkSet[int](s, i+1, false, t) + checkSet(s, i+1, false, t) } } func TestEmpty(t *testing.T) { s := NewUnorderedSet[int]() - checkEmpty[int](s, true, t) + checkEmpty(s, true, t) s.Insert(1) s.Insert(42) - checkEmpty[int](s, false, t) + checkEmpty(s, false, t) } func TestContains(t *testing.T) { s := NewUnorderedSet[int]() - checkSet[int](s, 0, true, t) + checkSet(s, 0, true, t) for i := 0; i < addsCount/2; i = i + 2 { s.Insert(i) @@ -65,21 +65,35 @@ func TestErase(t *testing.T) { s.Insert(i) } - checkSet[int](s, addsCount, false, t) + checkSet(s, addsCount, false, t) for i := 0; i < addsCount; i++ { - checkSet[int](s, addsCount-i, false, t) + checkSet(s, addsCount-i, false, t) s.Erase(i) } - checkSet[int](s, 0, true, t) + checkSet(s, 0, true, t) for i := 0; i < addsCount; i++ { - checkSet[int](s, 0, true, t) + checkSet(s, 0, true, t) s.Erase(i) } } +func TestClear(t *testing.T) { + s := NewUnorderedSet[int]() + + for i := 0; i < addsCount; i++ { + s.Insert(i) + } + + checkSet(s, addsCount, false, t) + + s.Clear() + + checkEmpty(s, true, t) +} + func checkSet[T comparable](s *UnorderedSet[T], size int, isEmpty bool, t *testing.T) { checkSize(s, size, t) checkEmpty(s, isEmpty, t) @@ -87,7 +101,7 @@ func checkSet[T comparable](s *UnorderedSet[T], size int, isEmpty bool, t *testi func checkSize[T comparable](s *UnorderedSet[T], size int, t *testing.T) { if size != s.Size() { - t.Errorf("Expected unordered_set size %d, got %d", size, s.Size()) + t.Errorf("Expected UnorderedSet size %d, got %d", size, s.Size()) } } diff --git a/errors.go b/errors.go new file mode 100644 index 0000000..29442ae --- /dev/null +++ b/errors.go @@ -0,0 +1,12 @@ +// Copyright 2021. The GTL Authors. All rights reserved. +// https://github.com/modern-dev/gtl +// Use of this source code is governed by the MIT +// license that can be found in the LICENSE file. + +package gtl + +import "errors" + +var ( + OutOfRange = errors.New("out-of-range error") +) diff --git a/set.go2 b/set.go2 deleted file mode 100644 index 6dd4a3f..0000000 --- a/set.go2 +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2020. The GTL Authors. All rights reserved. -// https://github.com/modern-dev/gtl -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE file. - -package gtl - -// Set is unordered set based on standard map -// It can contain comparable elements only -type Set[T comparable] struct { - table map[T]bool -} - -// NewSet creates an empty set. -func NewSet[T comparable]() *Set[T] { - return &Set[T]{table: map[T]bool{}} -} - -// Len returns the number of elements in the container. -// Complexity - O(1). -func (s *Set[T]) Len() int { - return len(s.table) -} - -// IsEmpty checks if there are elements in Set. -// Complexity - O(1). -// Returns true if the set is empty, false otherwise. -func (s *Set[T]) IsEmpty() bool { - return s.Len() == 0 -} - -// NotEmpty checks if there are no elements in Set. -// Complexity - O(1). -// Returns true if there are elements in set, false otherwise. -func (s *Set[T]) NotEmpty() bool { - return !s.IsEmpty() -} - -// Add inserts element into Set. -// Complexity - O(1). -func (s *Set[T]) Add(item T) { - s.table[item] = true -} - -// Contains checks if Set contains given element. -// Complexity - O(1). -// returns true if Set includes the element, false otherwise. -func (s *Set[T]) Contains(item T) bool { - _, exists := s.table[item] - - return exists -} - -// Delete deletes the element from set if it contains an element -// does nothing otherwise. -// Complexity - O(1). -func (s *Set[T]) Delete(item T) { - if s.Contains(item) { - delete(s.table, item) - } -} diff --git a/set_test.go2 b/set_test.go2 deleted file mode 100644 index 212e6b2..0000000 --- a/set_test.go2 +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2020. The GTL Authors. All rights reserved. -// https://github.com/modern-dev/gtl -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE file. - -package gtl - -import ( - "testing" -) - -const addsCount = 3000 - -func TestNewSet(t *testing.T) { - s := NewSet[int]() - - checkSet[int](s, 0, true, t) -} - -func TestAdd(t *testing.T) { - s := NewSet[int]() - - checkSet[int](s, 0, true, t) - for i := 0; i < addsCount; i++ { - s.Add(i) - checkSet[int](s, i+1, false, t) - } -} - -func TestIsEmpty(t *testing.T) { - s := NewSet[int]() - - checkIsEmpty[int](s, true, t) - - s.Add(1) - s.Add(42) - - checkIsEmpty[int](s, false, t) -} - -func TestNotEmpty(t *testing.T) { - s := NewSet[int]() - - checkNotEmpty[int](s, false, t) - - s.Add(0) - s.Add(35) - - checkNotEmpty[int](s, true, t) -} - -func TestContains(t *testing.T) { - s := NewSet[int]() - - checkSet[int](s, 0, true, t) - - for i := 0; i < addsCount/2; i = i + 2 { - s.Add(i) - - if s.Contains(i) != true { - t.Errorf("Expected set to contain %d", i) - } - - if s.Contains(i+1) == true { - t.Errorf("Expected set to not contain %d", i+1) - } - } -} - -func TestDelete(t *testing.T) { - s := NewSet[int]() - - for i := 0; i < addsCount; i++ { - s.Add(i) - } - - checkSet[int](s, addsCount, false, t) - - for i := 0; i < addsCount; i++ { - checkSet[int](s, addsCount-i, false, t) - s.Delete(i) - } - - checkSet[int](s, 0, true, t) - - for i := 0; i < addsCount; i++ { - checkSet[int](s, 0, true, t) - s.Delete(i) - } -} - -func checkSet[T comparable](s *Set[T], size int, isEmpty bool, t *testing.T) { - checkSize(s, size, t) - checkIsEmpty(s, isEmpty, t) -} - -func checkSize[T comparable](s *Set[T], size int, t *testing.T) { - if size != s.Len() { - t.Errorf("Expected set size %d, got %d", size, s.Len()) - } -} - -func checkIsEmpty[T comparable](s *Set[T], isEmpty bool, t *testing.T) { - if isEmpty != s.IsEmpty() { - t.Errorf("Expected IsEmpty to be %v, got %v", isEmpty, s.IsEmpty()) - } -} - -func checkNotEmpty[T comparable](s *Set[T], notEmpty bool, t *testing.T) { - if notEmpty != s.NotEmpty() { - t.Errorf("Expected NotEmpty to be %v, got %v", notEmpty, s.NotEmpty()) - } -} diff --git a/sortedset.go2 b/sortedset.go2 deleted file mode 100644 index d2ca97b..0000000 --- a/sortedset.go2 +++ /dev/null @@ -1,59 +0,0 @@ -package gtl - -// SortedSet is ordered set based on red-black tree -// It can contain comparable elements only -type SortedSet[T any] struct { - t *Tree[T] -} - -// NewSortedSet Constructs new SortedSet with given comparator -// which will be used for elements ordering. -func NewSortedSet[T any](comparator func(a, b T) int) *SortedSet[T] { - return &SortedSet[T]{t: NewTree[T](comparator)} -} - -// Len returns the number of elements in the container. -// Complexity - O(1). -func (s *SortedSet[T]) Len() int { - return s.t.Len() -} - -// IsEmpty checks if there are elements in the Set. -// Complexity - O(1). -// Returns true if the set is empty, false otherwise. -func (s *SortedSet[T]) IsEmpty() bool { - return s.Len() == 0 -} - -// NotEmpty checks if there are no elements in the SortedSet. -// Complexity - O(1). -// Returns true if there are elements in the set, false otherwise. -func (s *SortedSet[T]) NotEmpty() bool { - return !s.IsEmpty() -} - -// Add inserts the element into the SortedSet. -// Has no effect if the element already exist. -// Complexity - O(1). -func (s *SortedSet[T]) Add(element T) { - if _, exist := s.t.Search(element); exist { - return - } - - s.t.Insert(element) -} - -// Contains checks if SortedSet contains given element. -// Complexity - O(1). -// returns true if SortedSet includes the element, false otherwise. -func (s *SortedSet[T]) Contains(element T) bool { - _, contains := s.t.Search(element) - return contains -} - -// Delete deletes the element from set if it contains an element -// does nothing otherwise. -// Complexity - O(1). -func (s *SortedSet[T]) Delete(element T) { - s.t.Delete(element) -} diff --git a/sortedset_test.go2 b/sortedset_test.go2 deleted file mode 100644 index d878d55..0000000 --- a/sortedset_test.go2 +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2020. The GTL Authors. All rights reserved. -// https://github.com/modern-dev/gtl -// Use of this source code is governed by the MIT -// license that can be found in the LICENSE file. - -package gtl - -import ( - "testing" -) - -const insertsCount = 3000 - -func sortedSetIntComparator(a, b int) int { - return a - b -} - -func TestNewSortedSet(t *testing.T) { - s := NewSortedSet[int](sortedSetIntComparator) - - checkSortedSet[int](s, 0, true, t) -} - -func TestSortedSetAdd(t *testing.T) { - s := NewSortedSet[int](sortedSetIntComparator) - - checkSortedSet[int](s, 0, true, t) - for i := 0; i < insertsCount; i++ { - s.Add(i) - checkSortedSet[int](s, i+1, false, t) - } -} - -func TestSortedSetIsEmpty(t *testing.T) { - s := NewSortedSet[int](sortedSetIntComparator) - - checkSortedSetIsEmpty[int](s, true, t) - - s.Add(1) - s.Add(42) - - checkSortedSetIsEmpty[int](s, false, t) -} - -func TestSortedSetNotEmpty(t *testing.T) { - s := NewSortedSet[int](sortedSetIntComparator) - - checkSortedSetNotEmpty[int](s, false, t) - - s.Add(0) - s.Add(35) - - checkSortedSetNotEmpty[int](s, true, t) -} - -func TestSortedSetContains(t *testing.T) { - s := NewSortedSet[int](sortedSetIntComparator) - - checkSortedSet[int](s, 0, true, t) - - for i := 0; i < insertsCount/2; i = i + 2 { - s.Add(i) - - if s.Contains(i) != true { - t.Errorf("Expected set to contain %d", i) - } - - if s.Contains(i+1) == true { - t.Errorf("Expected set to not contain %d", i+1) - } - } -} - -func TestSortedSetDelete(t *testing.T) { - s := NewSortedSet[int](sortedSetIntComparator) - - for i := 0; i < insertsCount; i++ { - s.Add(i) - } - - checkSortedSet[int](s, insertsCount, false, t) - - for i := 0; i < insertsCount; i++ { - checkSortedSet[int](s, insertsCount-i, false, t) - s.Delete(i) - } - - checkSortedSet[int](s, 0, true, t) - - for i := 0; i < insertsCount; i++ { - checkSortedSet[int](s, 0, true, t) - s.Delete(i) - } -} - -func checkSortedSet[T comparable](s *SortedSet[T], size int, isEmpty bool, t *testing.T) { - checkSortedSetSize(s, size, t) - checkSortedSetIsEmpty(s, isEmpty, t) -} - -func checkSortedSetSize[T comparable](s *SortedSet[T], size int, t *testing.T) { - if size != s.Len() { - t.Errorf("Expected set size %d, got %d", size, s.Len()) - } -} - -func checkSortedSetIsEmpty[T comparable](s *SortedSet[T], isEmpty bool, t *testing.T) { - if isEmpty != s.IsEmpty() { - t.Errorf("Expected IsEmpty to be %v, got %v", isEmpty, s.IsEmpty()) - } -} - -func checkSortedSetNotEmpty[T comparable](s *SortedSet[T], notEmpty bool, t *testing.T) { - if notEmpty != s.NotEmpty() { - t.Errorf("Expected NotEmpty to be %v, got %v", notEmpty, s.NotEmpty()) - } -}