diff --git a/hashmap.go b/hashmap.go new file mode 100644 index 0000000..0c4019c --- /dev/null +++ b/hashmap.go @@ -0,0 +1,125 @@ +package unify4go + +// HashMap is a generic hash map data structure that maps keys of type `K` to values of type `V`. +// `K` and `V` must be comparable types, meaning that they support comparison operators (like == and !=). +// The `items` field stores the actual map, which is used to store key-value pairs. +type HashMap[K, V comparable] struct { + items map[K]V +} + +// NewHashMap is a constructor function that initializes and returns a pointer to a new, empty `HashMap`. +// It creates a new map with keys of type `K` and values of type `V`. +// +// Generics are used to make this function flexible for any types of keys and values as long as they +// are comparable. The function ensures that the map is properly initialized before returning it. +// +// Example usage: +// +// hashMap := NewHashMap[string, int]() // Creates a HashMap with string keys and int values. +func NewHashMap[K, V comparable]() *HashMap[K, V] { + hash := &HashMap[K, V]{ + items: make(map[K]V), + } + return hash +} + +// Put adds a new key-value pair to the HashMap. If the key already exists, its value is updated. +// Parameters: +// - `key`: The key to be added or updated in the map. +// - `value`: The value to be associated with the key. +// +// Example: +// +// hashMap.Put("apple", 5) // Inserts or updates the value of "apple" to 5. +func (hash *HashMap[K, V]) Put(key K, value V) { + hash.items[key] = value +} + +// Get retrieves the value associated with the given key from the HashMap. +// If the key exists, it returns the corresponding value. If the key does not exist, it returns the zero value for the type `V`. +// Parameters: +// - `key`: The key whose associated value is to be returned. +// +// Returns: +// - The value associated with the key, or the zero value for `V` if the key is not found. +// +// Example: +// +// value := hashMap.Get("apple") // Retrieves the value associated with "apple". +func (hash *HashMap[K, V]) Get(key K) (value V) { + return hash.items[key] +} + +// Remove deletes the key-value pair from the HashMap for the specified key. +// If the key does not exist, no action is taken. +// Parameters: +// - `key`: The key to be removed from the map. +// +// Example: +// +// hashMap.Remove("apple") // Removes the "apple" key and its associated value. +func (hash *HashMap[K, V]) Remove(key K) { + delete(hash.items, key) +} + +// Clear removes all key-value pairs from the HashMap, effectively resetting it to an empty map. +// +// Example: +// +// hashMap.Clear() // Clears the map, removing all entries. +func (hash *HashMap[K, V]) Clear() { + hash.items = make(map[K]V) +} + +// Size returns the number of key-value pairs currently stored in the HashMap. +// Returns: +// - The number of key-value pairs in the map. +// +// Example: +// +// size := hashMap.Size() // Gets the size of the map. +func (hash *HashMap[K, V]) Size() int { + return len(hash.items) +} + +// IsEmpty checks if the HashMap is empty (i.e., contains no key-value pairs). +// Returns: +// - `true` if the map is empty, `false` otherwise. +// +// Example: +// +// isEmpty := hashMap.IsEmpty() // Returns true if the map is empty. +func (hash *HashMap[K, V]) IsEmpty() bool { + return len(hash.items) == 0 +} + +// ContainsKey checks whether the specified key exists in the HashMap. +// Parameters: +// - `key`: The key to check for existence in the map. +// +// Returns: +// - `true` if the key exists in the map, `false` otherwise. +// +// Example: +// +// exists := hashMap.ContainsKey("apple") // Checks if the key "apple" exists in the map. +func (hash *HashMap[K, V]) ContainsKey(key K) bool { + _, ok := hash.items[key] + return ok +} + +// KeySet returns a slice of all keys currently stored in the HashMap. +// Returns: +// - A slice containing all keys in the map. +// +// Example: +// +// keys := hashMap.KeySet() // Returns all the keys in the map. +func (hash *HashMap[K, V]) KeySet() []K { + keys := make([]K, hash.Size()) + i := 0 + for key := range hash.items { + keys[i] = key + } + return keys +} diff --git a/hashset.go b/hashset.go new file mode 100644 index 0000000..1e391d9 --- /dev/null +++ b/hashset.go @@ -0,0 +1,234 @@ +package unify4go + +import "fmt" + +// itemExists is an empty struct used as a placeholder for values in the `HashSet` map. +// Using an empty struct saves memory, as it does not allocate any space in Go. +var itemExists struct{} + +// HashSet is a generic set data structure that stores unique elements of type `T`. +// It is implemented using a map where the keys are the elements and the values are +// empty structs (`struct{}`), which is an efficient way to represent a set in Go. +// The type `T` must be comparable, meaning it can be compared using == and !=. +type HashSet[T comparable] struct { + items map[T]struct{} +} + +// NewHashSet is a constructor function that creates a new `HashSet` and optionally adds +// any provided elements to the set. +// Parameters: +// - `elements`: A variadic list of elements of type `T` to initialize the set with (optional). +// +// Returns: +// - A pointer to the newly created `HashSet`. +// +// Example usage: +// +// hashSet := NewHashSet(1, 2, 3) // Creates a set with initial elements 1, 2, and 3. +func NewHashSet[T comparable](elements ...T) *HashSet[T] { + hash := &HashSet[T]{ + items: make(map[T]struct{}), + } + hash.AddAll(elements...) + return hash +} + +// Add inserts a new element into the HashSet. If the element already exists, no action is taken. +// Parameters: +// - `element`: The element to be added to the set. +// +// Example usage: +// +// hashSet.Add(4) // Adds the element 4 to the set. +func (hash *HashSet[T]) Add(element T) { + hash.items[element] = itemExists +} + +// AddAll inserts multiple elements into the HashSet. If any element already exists, it is ignored. +// Parameters: +// - `elements`: A variadic list of elements of type `T` to add to the set. +// +// Example usage: +// +// hashSet.AddAll(4, 5, 6) // Adds elements 4, 5, and 6 to the set. +func (hash *HashSet[T]) AddAll(elements ...T) { + for _, e := range elements { + hash.Add(e) + } +} + +// Remove deletes the specified element from the HashSet. +// If the element does not exist, no action is taken. +// Parameters: +// - `element`: The element to be removed from the set. +// +// Example usage: +// +// hashSet.Remove(5) // Removes element 5 from the set. +func (hash *HashSet[T]) Remove(element T) { + delete(hash.items, element) +} + +// RemoveAll deletes multiple elements from the HashSet. +// Parameters: +// - `elements`: A variadic list of elements to be removed from the set. +// +// Example usage: +// +// hashSet.RemoveAll(2, 4, 6) // Removes elements 2, 4, and 6 from the set. +func (hash *HashSet[T]) RemoveAll(elements ...T) { + for _, e := range elements { + hash.Remove(e) + } +} + +// Clear removes all elements from the HashSet, resetting it to an empty set. +// +// Example usage: +// +// hashSet.Clear() // Clears all elements from the set. +func (hash *HashSet[T]) Clear() { + hash.items = make(map[T]struct{}) +} + +// Size returns the number of elements currently stored in the HashSet. +// Returns: +// - The number of elements in the set. +// +// Example usage: +// +// size := hashSet.Size() // Returns the size of the set. +func (hash *HashSet[T]) Size() int { + return len(hash.items) +} + +// IsEmpty checks if the HashSet contains any elements. +// Returns: +// - `true` if the set is empty, `false` otherwise. +// +// Example usage: +// +// isEmpty := hashSet.IsEmpty() // Returns true if the set is empty. +func (hash *HashSet[T]) IsEmpty() bool { + return len(hash.items) == 0 +} + +// Contains checks whether the specified element exists in the HashSet. +// Parameters: +// - `element`: The element to check for existence in the set. +// +// Returns: +// - `true` if the element is present in the set, `false` otherwise. +// +// Example usage: +// +// exists := hashSet.Contains(3) // Checks if element 3 is in the set. +func (hash *HashSet[T]) Contains(element T) bool { + _, ok := hash.items[element] + return ok +} + +// Intersection returns a new HashSet containing only the elements present in both the current set and another set. +// Parameters: +// - `another`: Another `HashSet` to find the intersection with. +// +// Returns: +// - A new `HashSet` containing the intersection of the two sets. +// +// Example usage: +// +// resultSet := hashSet.Intersection(anotherSet) // Returns the intersection of two sets. +func (hash *HashSet[T]) Intersection(another *HashSet[T]) *HashSet[T] { + result := NewHashSet[T]() + if hash.Size() <= another.Size() { + for item := range hash.items { + if _, contains := another.items[item]; contains { + result.Add(item) + } + } + return result + } + for item := range another.items { + if _, contains := hash.items[item]; contains { + result.Add(item) + } + } + return result +} + +// Union returns a new HashSet that contains all elements from both the current set and another set. +// Parameters: +// - `another`: Another `HashSet` to combine with the current set. +// +// Returns: +// - A new `HashSet` containing the union of the two sets. +// +// Example usage: +// +// resultSet := hashSet.Union(anotherSet) // Returns the union of two sets. +func (hash *HashSet[T]) Union(another *HashSet[T]) *HashSet[T] { + result := NewHashSet[T]() + for item := range hash.items { + result.Add(item) + } + for item := range another.items { + result.Add(item) + } + return result +} + +// Difference returns a new HashSet containing the elements that are in the current set but not in another set. +// Parameters: +// - `another`: Another `HashSet` to compare against. +// +// Returns: +// - A new `HashSet` containing the difference between the current set and the other set. +// +// Example usage: +// +// resultSet := hashSet.Difference(anotherSet) // Returns the difference between two sets. +func (hash *HashSet[T]) Difference(another *HashSet[T]) *HashSet[T] { + result := NewHashSet[T]() + for item := range hash.items { + if _, exist := another.items[item]; !exist { + result.Add(item) + } + } + return result +} + +// Slice converts the HashSet into a slice of elements. +// Returns: +// - A slice containing all elements in the set. +// +// Example usage: +// +// slice := hashSet.Slice() // Converts the set to a slice. +func (hash *HashSet[T]) Slice() []T { + slices := make([]T, hash.Size()) + i := 0 + for val := range hash.items { + slices[i] = val + i++ + } + return slices +} + +// String returns a string representation of the HashSet, with elements separated by commas. +// Returns: +// - A string that represents the elements in the set. +// +// Example usage: +// +// str := hashSet.String() // Returns a string representation of the set. +func (hash *HashSet[T]) String() string { + s := "" + for val := range hash.items { + if IsEmpty(s) { + s = fmt.Sprintf("%v", val) + } else { + s = fmt.Sprintf("%s,%v", s, val) + } + } + return s +} diff --git a/stack.go b/stack.go new file mode 100644 index 0000000..0aff7ce --- /dev/null +++ b/stack.go @@ -0,0 +1,94 @@ +package unify4go + +// Stack is a generic stack data structure that stores elements of type `T`. +// It provides basic stack operations like push, pop, and peek. +// The type `T` must be comparable, allowing the stack to handle any type that supports equality comparison. +type Stack[T comparable] struct { + items []T +} + +// NewStack creates and returns a new, empty stack. +// Returns: +// - A pointer to an empty `Stack`. +// +// Example usage: +// +// stack := NewStack[int]() // Creates a new empty stack of integers. +func NewStack[T comparable]() *Stack[T] { + return &Stack[T]{items: make([]T, 0)} +} + +// Push adds a new element to the top of the stack. +// Parameters: +// - `element`: The element to be added to the stack. +// +// Example usage: +// +// stack.Push(5) // Pushes the value 5 onto the stack. +func (stack *Stack[T]) Push(element T) { + stack.items = append(stack.items, element) +} + +// Peek returns the top element of the stack without removing it. +// If the stack is empty, it returns the zero value for type `T`. +// Returns: +// - The top element of the stack, or the zero value of `T` if the stack is empty. +// +// Example usage: +// +// top := stack.Peek() // Gets the top element of the stack without removing it. +func (stack *Stack[T]) Peek() T { + var lastElement T + if len(stack.items) > 0 { + lastElement = stack.items[len(stack.items)-1] + } + return lastElement +} + +// Pop removes and returns the top element of the stack. +// If the stack is empty, it returns the zero value for type `T`. +// Returns: +// - The top element of the stack, or the zero value of `T` if the stack is empty. +// +// Example usage: +// +// top := stack.Pop() // Removes and returns the top element of the stack. +func (stack *Stack[T]) Pop() T { + var lastElement T + if len(stack.items) > 0 { + lastElement = stack.items[len(stack.items)-1] + stack.items = stack.items[:len(stack.items)-1] + } + return lastElement +} + +// IsEmpty checks whether the stack contains any elements. +// Returns: +// - `true` if the stack is empty, `false` otherwise. +// +// Example usage: +// +// isEmpty := stack.IsEmpty() // Returns true if the stack is empty. +func (stack *Stack[T]) IsEmpty() bool { + return len(stack.items) == 0 +} + +// Size returns the number of elements currently in the stack. +// Returns: +// - The number of elements in the stack. +// +// Example usage: +// +// size := stack.Size() // Returns the size of the stack. +func (stack *Stack[T]) Size() int { + return len(stack.items) +} + +// Clear removes all elements from the stack, leaving it empty. +// +// Example usage: +// +// stack.Clear() // Clears all elements from the stack. +func (stack *Stack[T]) Clear() { + stack.items = make([]T, 0) +} diff --git a/test/hashmap_test.go b/test/hashmap_test.go new file mode 100644 index 0000000..3d0f5de --- /dev/null +++ b/test/hashmap_test.go @@ -0,0 +1,226 @@ +package example_test + +import ( + "testing" + + "github.com/sivaosorg/unify4go" +) + +func TestNewHashMap(t *testing.T) { + hashMap := unify4go.NewHashMap[int, string]() + if hashMap == nil { + t.Errorf("Hashmap is nil") + return + } +} + +func TestPut(t *testing.T) { + hashMap := unify4go.NewHashMap[int, string]() + if hashMap == nil { + t.Errorf("Hashmap is nil") + return + } + + hashMap.Put(1, "test") + hashMap.Put(2, "test 2") + + if hashMap.Size() != 2 { + t.Errorf("Expected size of map to be %d but got %d", 2, hashMap.Size()) + } + + if !hashMap.ContainsKey(1) { + t.Errorf("Map should contain key: %v", 1) + } + + if !hashMap.ContainsKey(2) { + t.Errorf("Map should contain key: %v", 2) + } +} + +func TestGet(t *testing.T) { + hashMap := unify4go.NewHashMap[int, string]() + if hashMap == nil { + t.Errorf("Hashmap is nil") + return + } + + hashMap.Put(1, "test") + hashMap.Put(2, "test 2") + + if key := hashMap.Get(1); key != "test" { + t.Errorf("Expected value for key: %v to be 'test' but got '%s'", 1, key) + } + + if key := hashMap.Get(2); key != "test 2" { + t.Errorf("Expected value for key: %v to be 'test 2' but got '%s'", 2, key) + } +} + +func TestRemove(t *testing.T) { + hashMap := unify4go.NewHashMap[int, string]() + if hashMap == nil { + t.Errorf("Hashmap is nil") + return + } + + hashMap.Put(1, "test") + hashMap.Put(2, "test 2") + + hashMap.Remove(1) + + if ok := hashMap.ContainsKey(1); ok { + t.Errorf("Removed key still exists in the hashmap") + } + + if key := hashMap.Get(2); key != "test 2" { + t.Errorf("Expected value for key: %v to be 'test 2' but got '%s'", 2, key) + } +} + +func TestClear(t *testing.T) { + hashMap := unify4go.NewHashMap[int, string]() + if hashMap == nil { + t.Errorf("Hashmap is nil") + return + } + + hashMap.Put(1, "test") + hashMap.Put(2, "test 2") + + hashMap.Clear() + + if res := hashMap.IsEmpty(); !res { + t.Errorf("Expected hashmap to be empty after clearing it") + } +} + +func TestKeySet(t *testing.T) { + hashMap := unify4go.NewHashMap[int, string]() + if hashMap == nil { + t.Errorf("Hashmap is nil") + return + } + + hashMap.Put(1, "test") + hashMap.Put(2, "test 2") + + keys := hashMap.KeySet() + + if len(keys) != 2 { + t.Errorf("Expected key set to contain 2 keys but got %d", len(keys)) + } +} + +func BenchmarkHashMapPut100(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 100; j++ { + hashMap.Put(j, "test") + } + } +} + +func BenchmarkHashMapPut10000(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 10000; j++ { + hashMap.Put(j, "test") + } + } +} + +func BenchmarkHashMapPut1000000(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 1000000; j++ { + hashMap.Put(j, "test") + } + } +} + +func BenchmarkHashMapRemove100(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 100; j++ { + hashMap.Put(j, "test") + } + b.StartTimer() + for j := 0; j < 100; j++ { + hashMap.Remove(j) + } + } +} + +func BenchmarkHashMapRemove10000(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 10000; j++ { + hashMap.Put(j, "test") + } + b.StartTimer() + for j := 0; j < 10000; j++ { + hashMap.Remove(j) + } + } +} + +func BenchmarkHashMapRemove1000000(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 1000000; j++ { + hashMap.Put(j, "test") + } + b.StartTimer() + for j := 0; j < 1000000; j++ { + hashMap.Remove(j) + } + } +} + +func BenchmarkHashMapContains100(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + for j := 0; j < 100; j++ { + hashMap.Put(j, "test") + } + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = hashMap.ContainsKey(50) + } +} + +func BenchmarkHashMapContains10000(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + for j := 0; j < 10000; j++ { + hashMap.Put(j, "test") + } + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = hashMap.ContainsKey(5000) + } +} + +func BenchmarkHashMapContains1000000(b *testing.B) { + hashMap := unify4go.NewHashMap[int, string]() + for j := 0; j < 1000000; j++ { + hashMap.Put(j, "test") + } + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = hashMap.ContainsKey(500000) + } +} diff --git a/test/hashset_test.go b/test/hashset_test.go new file mode 100644 index 0000000..376bd02 --- /dev/null +++ b/test/hashset_test.go @@ -0,0 +1,317 @@ +package example_test + +import ( + "testing" + + "github.com/sivaosorg/unify4go" +) + +func TestNewHashSet(t *testing.T) { + hashSet := unify4go.NewHashSet[int]() + if hashSet == nil { + t.Errorf("Hashset is nil") + return + } +} + +func TestHashSet_Add(t *testing.T) { + hashSet := unify4go.NewHashSet[string]() + hashSet.Add("test1") + hashSet.Add("test2") + hashSet.Add("test3") + hashSet.Add("test4") + + if hashSet.Size() != 4 { + t.Errorf("Expected size of set to be %d but got %d", 4, hashSet.Size()) + } +} + +func TestHashSet_Remove(t *testing.T) { + hashSet := unify4go.NewHashSet[string]() + hashSet.Add("test1") + hashSet.Add("test2") + hashSet.Remove("test2") + hashSet.Add("test3") + + if hashSet.Size() != 2 { + t.Errorf("Expected size of set to be %d but got %d", 2, hashSet.Size()) + } + + if hashSet.Contains("test") { + t.Errorf("Expected set to not contain test") + } +} + +func TestHashSet_AddAll(t *testing.T) { + hashSet := unify4go.NewHashSet[string]() + hashSet.AddAll("test1", "test2", "test3", "test4") + + if hashSet.Size() != 4 { + t.Errorf("Expected size of set to be %d but got %d", 4, hashSet.Size()) + } +} + +func TestHashSet_RemoveAll(t *testing.T) { + hashSet := unify4go.NewHashSet[string]() + hashSet.AddAll("test1", "test2", "test3", "test4") + hashSet.RemoveAll("test1", "test3") + hashSet.RemoveAll("test1", "test2", "test4") + + if !hashSet.IsEmpty() { + t.Errorf("Expected set to be empty") + } +} + +func TestHashSet_Clear(t *testing.T) { + hashSet := unify4go.NewHashSet[string]() + hashSet.AddAll("test1", "test2", "test3", "test4") + hashSet.Clear() + + if !hashSet.IsEmpty() { + t.Errorf("Expected set to be empty") + } +} + +func TestHashSet_IntersectionFirstSetBiggerSize(t *testing.T) { + hashSetA := unify4go.NewHashSet[int](1, 2, 3, 4) + hashSetB := unify4go.NewHashSet[int](2, 5) + + NewHashSet := hashSetA.Intersection(hashSetB) + + if NewHashSet.Size() != 1 { + t.Errorf("Expected intersection size to be %d but got %d", 1, NewHashSet.Size()) + } + + if !NewHashSet.Contains(2) { + t.Errorf("Expected intersection to contain value 2") + } + + if hashSetA.Size() != 4 { + t.Errorf("Original set should remain unchanged after operation") + } + + if hashSetB.Size() != 2 { + t.Errorf("Original set should remain unchanged after operation") + } +} + +func TestHashSet_IntersectionFirstSetSmallerSize(t *testing.T) { + hashSetA := unify4go.NewHashSet[int](2, 5) + hashSetB := unify4go.NewHashSet[int](1, 2, 3, 4) + + NewHashSet := hashSetA.Intersection(hashSetB) + + if NewHashSet.Size() != 1 { + t.Errorf("Expected intersection size to be %d but got %d", 1, NewHashSet.Size()) + } + + if !NewHashSet.Contains(2) { + t.Errorf("Expected intersection to contain value 2") + } + + if hashSetA.Size() != 2 { + t.Errorf("Original set should remain unchanged after operation") + } + + if hashSetB.Size() != 4 { + t.Errorf("Original set should remain unchanged after operation") + } +} + +func TestHashSet_Union(t *testing.T) { + hashSetA := unify4go.NewHashSet[int](1, 2, 4) + hashSetB := unify4go.NewHashSet[int](2, 3) + + NewHashSet := hashSetA.Union(hashSetB) + + if NewHashSet.Size() != 4 { + t.Errorf("Expected union size to be %d but got %d", 4, NewHashSet.Size()) + } + + if !NewHashSet.Contains(1) { + t.Errorf("Expected union to contain value 1") + } + + if !NewHashSet.Contains(2) { + t.Errorf("Expected union to contain value 2") + } + + if !NewHashSet.Contains(3) { + t.Errorf("Expected union to contain value 3") + } + + if !NewHashSet.Contains(4) { + t.Errorf("Expected union to contain value 4") + } + + if hashSetA.Size() != 3 { + t.Errorf("Original set should remain unchanged after operation") + } + + if hashSetB.Size() != 2 { + t.Errorf("Original set should remain unchanged after operation") + } + +} + +func TestHashSet_Difference(t *testing.T) { + hashSetA := unify4go.NewHashSet[int](1, 2, 4) + hashSetB := unify4go.NewHashSet[int](2, 3) + + NewHashSet := hashSetA.Difference(hashSetB) + + if NewHashSet.Size() != 2 { + t.Errorf("Expected difference size to be %d but got %d", 2, NewHashSet.Size()) + } + + if !NewHashSet.Contains(1) { + t.Errorf("Expected union to contain value 1") + } + + if !NewHashSet.Contains(4) { + t.Errorf("Expected union to contain value 4") + } + + if hashSetA.Size() != 3 { + t.Errorf("Original set should remain unchanged after operation") + } + + if hashSetB.Size() != 2 { + t.Errorf("Original set should remain unchanged after operation") + } +} + +func TestHashSet_ToString(t *testing.T) { + hashSet := unify4go.NewHashSet[string]("a", "b") + expectedString1 := "a,b" + expectedString2 := "b,a" + + result := hashSet.String() + + if result != expectedString1 && result != expectedString2 { + t.Errorf("Expected string to be %s or %s but got %s", expectedString1, expectedString2, result) + } +} + +func TestHashSet_ToSlice(t *testing.T) { + hashSet := unify4go.NewHashSet[int](1, 2, 3) + slice := hashSet.Slice() + + if len(slice) != hashSet.Size() { + t.Errorf("Expected slice length to be %d but got %d", hashSet.Size(), len(slice)) + } +} + +func BenchmarkHashSetAdd100(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 100; j++ { + hashSet.Add(j) + } + } +} + +func BenchmarkHashSetAdd10000(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 10000; j++ { + hashSet.Add(j) + } + } +} + +func BenchmarkHashSetAdd1000000(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 1000000; j++ { + hashSet.Add(j) + } + } +} + +func BenchmarkHashSetRemove100(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 100; j++ { + hashSet.Add(j) + } + b.StartTimer() + for j := 0; j < 100; j++ { + hashSet.Remove(j) + } + } +} + +func BenchmarkHashSetRemove10000(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 10000; j++ { + hashSet.Add(j) + } + b.StartTimer() + for j := 0; j < 10000; j++ { + hashSet.Remove(j) + } + } +} + +func BenchmarkHashSetRemove1000000(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 1000000; j++ { + hashSet.Add(j) + } + b.StartTimer() + for j := 0; j < 1000000; j++ { + hashSet.Remove(j) + } + } +} + +func BenchmarkHashSetContains100(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + for j := 0; j < 100; j++ { + hashSet.Add(j) + } + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = hashSet.Contains(50) + } +} + +func BenchmarkHashSetContains10000(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + for j := 0; j < 10000; j++ { + hashSet.Add(j) + } + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = hashSet.Contains(5000) + } +} + +func BenchmarkHashSetContains1000000(b *testing.B) { + hashSet := unify4go.NewHashSet[int]() + for j := 0; j < 1000000; j++ { + hashSet.Add(j) + } + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + _ = hashSet.Contains(500000) + } +} diff --git a/test/stack_test.go b/test/stack_test.go new file mode 100644 index 0000000..7731a2c --- /dev/null +++ b/test/stack_test.go @@ -0,0 +1,144 @@ +package example_test + +import ( + "testing" + + "github.com/sivaosorg/unify4go" +) + +func TestNewStack(t *testing.T) { + stack := unify4go.NewStack[int]() + if stack == nil { + t.Error("stack is nil") + } +} + +func TestPush(t *testing.T) { + stack := unify4go.NewStack[int]() + stack.Push(1) + stack.Push(2) + stack.Push(3) + + if stack.Size() != 3 { + t.Error("stack size is not 3") + } +} + +func TestPop(t *testing.T) { + stack := unify4go.NewStack[int]() + stack.Push(1) + + if stack.Pop() != 1 { + t.Error("stack top is not 1") + } + + if !stack.IsEmpty() { + t.Error("stack is not empty") + } +} + +func TestPeek(t *testing.T) { + stack := unify4go.NewStack[int]() + stack.Push(1) + stack.Push(2) + stack.Push(3) + + if stack.Peek() != 3 { + t.Error("stack top is not 3") + } + + if stack.Size() != 3 { + t.Error("stack size is not 3") + } +} + +func TestStackClear(t *testing.T) { + stack := unify4go.NewStack[int]() + stack.Push(1) + stack.Push(2) + stack.Push(3) + + stack.Clear() + + if !stack.IsEmpty() { + t.Error("stack is not empty") + } +} + +func BenchmarkStackPush100(b *testing.B) { + stack := unify4go.NewStack[int]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 100; j++ { + stack.Push(j) + } + } +} + +func BenchmarkStackPush10000(b *testing.B) { + stack := unify4go.NewStack[int]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 10000; j++ { + stack.Push(j) + } + } +} + +func BenchmarkStackPush1000000(b *testing.B) { + stack := unify4go.NewStack[int]() + b.StopTimer() + b.StartTimer() + for i := 0; i < b.N; i++ { + for j := 0; j < 1000000; j++ { + stack.Push(j) + } + } +} + +func BenchmarkStackPop100(b *testing.B) { + stack := unify4go.NewStack[int]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 100; j++ { + stack.Push(j) + } + b.StartTimer() + for j := 0; j < 100; j++ { + stack.Pop() + } + } +} + +func BenchmarkStackPop10000(b *testing.B) { + stack := unify4go.NewStack[int]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 10000; j++ { + stack.Push(j) + } + b.StartTimer() + for j := 0; j < 10000; j++ { + stack.Pop() + } + } +} + +func BenchmarkStackPop1000000(b *testing.B) { + stack := unify4go.NewStack[int]() + + for i := 0; i < b.N; i++ { + b.StopTimer() + for j := 0; j < 1000000; j++ { + stack.Push(j) + } + b.StartTimer() + for j := 0; j < 1000000; j++ { + stack.Pop() + } + } +}