diff --git a/utils/simpleorderedmap.go b/utils/simpleorderedmap.go deleted file mode 100644 index a6155af91..000000000 --- a/utils/simpleorderedmap.go +++ /dev/null @@ -1,82 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ - -package utils - -// OrderedMap is a map that maintains the order of its key-value pairs. -type OrderedMap[K comparable, V any] struct { - keys []K // keys holds the keys in order of their insertion. - values map[K]V // values is a map of key-value pairs. -} - -// NewOrderedMap creates a new ordered map and returns a pointer to it. -func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] { - return &OrderedMap[K, V]{ - keys: make([]K, 0), // Initialize an empty slice for keys. - values: make(map[K]V), // Initialize an empty map for key-value pairs. - } -} - -// Set adds a new key-value pair to the ordered map. If the key already exists, it updates the value. -func (om *OrderedMap[K, V]) Set(key K, value V) { - // If the key does not exist in the map, append it to the keys slice. - if _, exists := om.values[key]; !exists { - om.keys = append(om.keys, key) - } - // Add or update the value for the key in the map. - om.values[key] = value -} - -// Get retrieves the value associated with the given key from the ordered map. -// It returns the value and a boolean indicating whether the key exists in the map. -func (om *OrderedMap[K, V]) Get(key K) (V, bool) { - // Retrieve the value for the key from the map. - val, ok := om.values[key] - return val, ok -} - -// Delete removes the key-value pair associated with the given key from the ordered map. -func (om *OrderedMap[K, V]) Delete(key K) { - // Iterate over the keys slice to find the key to delete. - for i, k := range om.keys { - // When the key is found, remove it from the slice. - if k == key { - om.keys = append(om.keys[:i], om.keys[i+1:]...) - break - } - } - // Remove the key-value pair from the map. - delete(om.values, key) -} - -// Keys returns all keys of the ordered map in order of their insertion. -func (om *OrderedMap[K, V]) Keys() []K { - return om.keys -} - -// Values returns all values of the ordered map in the order of their corresponding keys' insertion. -func (om *OrderedMap[K, V]) Values() []V { - // Initialize an empty slice to hold the values. - vals := make([]V, 0, len(om.values)) - - // Iterate over the keys in order and append the corresponding value to the values slice. - for _, key := range om.keys { - vals = append(vals, om.values[key]) - } - return vals -} diff --git a/utils/simpleorderedmap_test.go b/utils/simpleorderedmap_test.go deleted file mode 100644 index 2edc0f10f..000000000 --- a/utils/simpleorderedmap_test.go +++ /dev/null @@ -1,169 +0,0 @@ -/* -Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments -Copyright (C) ITsysCOM GmbH - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see -*/ -package utils - -import ( - "crypto/rand" - "reflect" - "testing" -) - -func TestOrderedMapSetGetDelete(t *testing.T) { - testCases := []struct { - key string - value string - }{ - {"shortKey", "shortValue"}, - {"longKeylongKeylongKeylongKeylongKeylongKey", "longValuelongValuelongValuelongValuelongValue"}, - {"keyWithSpecialCharacters!@#$%^&*()", "valueWithSpecialCharacters!@#$%^&*()"}, - {"", ""}, - } - - for _, tc := range testCases { - // Initialize a new OrderedMap for each test case - om := NewOrderedMap[string, string]() - - // Perform a set and a get for the initial key-value pair - om.Set(tc.key, tc.value) - val, ok := om.Get(tc.key) - if !ok || val != tc.value { - t.Errorf("Set key-value pair did not match Get result: expected %s, got %s", tc.value, val) - } - - // Update the value - newValue := tc.value + "updated" - om.Set(tc.key, newValue) - val, ok = om.Get(tc.key) - if !ok || val != newValue { - t.Errorf("Updated key-value pair did not match Get result: expected %s, got %s", newValue, val) - } - - // Delete the key - om.Delete(tc.key) - _, ok = om.Get(tc.key) - if ok { - t.Errorf("Deleted key was still found in map") - } - - // Try to get a non-existent key - _, ok = om.Get("non-existent key") - if ok { - t.Errorf("Non-existent key was found in map") - } - } -} - -func TestOrderedMapKeysValues(t *testing.T) { - // Initialize a new OrderedMap - om := NewOrderedMap[string, string]() - - // Set multiple key-value pairs - om.Set("key1", "value1") - om.Set("key2", "value2") - om.Set("key3", "value3") - - // Get the keys and values - keys := om.Keys() - values := om.Values() - - // Check the keys - expectedKeys := []string{"key1", "key2", "key3"} - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("Keys do not match expected keys: expected %v, received %v", expectedKeys, keys) - } - - // Check the values - expectedValues := []string{"value1", "value2", "value3"} - if !reflect.DeepEqual(values, expectedValues) { - t.Errorf("Values do not match expected values: expected %v, received %v", expectedValues, values) - } -} - -// Benchmark that emphasizes the difference in performance for simple values between -// OrderedNavigableMap and the generic OrderedMap. -// Sample usage: go test -bench=. -run=Benchmark_NavigableMaps -benchtime=5s -count 3 -benchmem -func BenchmarkOrderedMaps(b *testing.B) { - letterBytes := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" - - // Function to generate a random string of `strLen` length - randomString := func(strLen int) string { - byt := make([]byte, strLen) - rand.Read(byt) - - for i := range byt { - byt[i] = letterBytes[byt[i]%byte(len(letterBytes))] - } - return string(byt) - } - - // Function to generate a slice of n random strings - generateStringSlice := func(n int) []string { - randStrings := make([]string, n) - for i := range randStrings { - randStrings[i] = randomString(10) - } - return randStrings - } - - keys := generateStringSlice(100000) - values := generateStringSlice(100000) - - b.Run("Generic ordered map - Set", func(b *testing.B) { - genericOm := NewOrderedMap[string, string]() - b.ResetTimer() - for i := 0; i < b.N; i++ { - genericOm.Set(keys[i%len(keys)], values[i%len(values)]) - } - }) - b.Run("Generic ordered map - Get", func(b *testing.B) { - genericOm := NewOrderedMap[string, string]() - for i := 0; i < len(keys); i++ { - genericOm.Set(keys[i], values[i]) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = genericOm.Get(keys[i%len(keys)]) - } - }) - - b.Run("OrderedNavigableMap - Set", func(b *testing.B) { - onm := NewOrderedNavigableMap() - b.ResetTimer() - for i := 0; i < b.N; i++ { - onm.Set(&FullPath{ - Path: keys[i%len(keys)], - PathItems: NewPathItems([]string{keys[i%len(keys)]}), - }, NewNMData(values[i%len(values)])) - } - }) - b.Run("OrderedNavigableMap - Field+String", func(b *testing.B) { - onm := NewOrderedNavigableMap() - for i := 0; i < len(keys); i++ { - onm.Set(&FullPath{ - Path: keys[i], - PathItems: NewPathItems([]string{keys[i]}), - }, NewNMData(values[i%len(values)])) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - val, _ := onm.Field(NewPathItems([]string{keys[i%len(keys)]})) - _ = val.String() - } - }) - -}