Documentation
ΒΆ
Overview ΒΆ
Package genericmap provides a thread-safe, generic bidirectional map implementation.
The genericmap package offers a highly efficient map with both forward (key->value) and reverse (value->keys) lookup capabilities, designed specifically for Go 1.18+.
Features:
β’ Thread-safe concurrent access using sync.RWMutex β’ Generic type support for both keys and values β’ Efficient O(1) reverse lookups via prebuilt reverse index β’ Memory optimized with swap-and-truncate removal β’ Fully compatible with Go idioms
Basic Usage:
import "github.com/costa92/genericmap"
// Create empty map
m := genericmap.New[string, int]()
m.Set("apple", 5)
m.Set("banana", 2)
// Create with initial data
initial := map[string]int{"a": 1, "b": 2}
m := genericmap.New[string, int](initial)
// Forward lookup
value, exists := m.Get("apple")
// Reverse lookup
keys := m.GetKeys(5) // Gets all keys with value 5
// Thread-safe operations
m.Len() // Get map size
m.List() // Get all keys
m.Values() // Get all values
m.Remove("apple")
Concurrent Usage:
The map is safe for concurrent use from multiple goroutines without external locking. Reader goroutines use read locks, writer goroutines use write locks.
Example:
m := genericmap.New[int, string]()
go func() { m.Set(1, "admin") }()
go func() { fmt.Println(m.Len()) }()
go func() { keys := m.GetKeys("admin") }()
Performance Characteristics:
β’ Set: O(1) average case for new keys β’ Get: O(1) guaranteed β’ GetKeys: O(k) where k is number of keys for value β’ Remove: O(1) average case β’ Len: O(1)
Memory Usage:
The map maintains an additional reverse index, which uses O(n) space where n is the number of unique values in the map.
Package genericmap provides a thread-safe, generic bidirectional map implementation. It supports efficient forward lookups (key->value) and reverse lookups (value->keys).
Example ΒΆ
// Create empty map
m := New[string, int]()
fmt.Printf("Empty map length: %d\n", m.Len())
// Create with initial data
initial := map[string]int{"apple": 5, "banana": 2, "cherry": 5}
m = New[string, int](initial)
fmt.Printf("Initialized map length: %d\n", m.Len())
// Sort keys for consistent output
keys := m.GetKeys(5)
sort.Strings(keys)
fmt.Printf("Keys for value 5: %v\n", keys)
Output: Empty map length: 0 Initialized map length: 3 Keys for value 5: [apple cherry]
Index ΒΆ
Examples ΒΆ
Constants ΒΆ
This section is empty.
Variables ΒΆ
This section is empty.
Functions ΒΆ
This section is empty.
Types ΒΆ
type Map ΒΆ
type Map[K comparable, V comparable] struct { // contains filtered or unexported fields }
Map is a thread-safe, generic map with bidirectional lookup capabilities. It supports both key-to-value and value-to-keys operations efficiently.
Example (BasicUsage) ΒΆ
ExampleBasicUsage demonstrates basic usage of the genericmap package.
// Create a new map
m := New[string, int]()
// Add key-value pairs
m.Set("apple", 5)
m.Set("banana", 2)
m.Set("cherry", 5)
// Retrieve values
if value, exists := m.Get("apple"); exists {
fmt.Printf("apple has %d items\n", value)
}
// List all keys (sorted for consistent output)
keys := m.List()
sort.Strings(keys)
fmt.Printf("All keys: %v\n", keys)
// List all values (sorted for consistent output)
values := m.Values()
sort.Ints(values)
fmt.Printf("All values: %v\n", values)
// Reverse lookup - find keys for a value (sorted for consistent output)
keysWithValue5 := m.GetKeys(5)
sort.Strings(keysWithValue5)
fmt.Printf("Keys with value 5: %v\n", keysWithValue5)
// Get map size
fmt.Printf("Map contains %d items\n", m.Len())
// Remove an item
removed := m.Remove("banana")
fmt.Printf("Removed banana: %t, new size: %d\n", removed, m.Len())
Output: apple has 5 items All keys: [apple banana cherry] All values: [2 5 5] Keys with value 5: [apple cherry] Map contains 3 items Removed banana: true, new size: 2
Example (Concurrent) ΒΆ
ExampleConcurrent demonstrates thread-safe concurrent usage.
m := New[int, string]()
var wg sync.WaitGroup
// Multiple goroutines writing
wg.Add(5)
for i := 0; i < 5; i++ {
go func(id int) {
defer wg.Done()
m.Set(id, fmt.Sprintf("item-%d", id))
}(i)
}
// Multiple goroutines reading
wg.Add(5)
for i := 0; i < 5; i++ {
go func() {
defer wg.Done()
for j := 0; j < 10; j++ {
_ = m.Len()
_ = m.List()
_ = m.GetKeys("test")
}
}()
}
wg.Wait()
fmt.Printf("Concurrent operations completed: %d items\n", m.Len())
Output: Concurrent operations completed: 5 items
Example (InitialData) ΒΆ
ExampleInitialData demonstrates creating a map with initial data.
// Create with initial data
initial := map[string]int{
"apple": 5,
"banana": 2,
"cherry": 5,
}
m := New[string, int](initial)
fmt.Printf("Initial data loaded: %d items\n", m.Len())
keys := m.GetKeys(5)
fmt.Printf("Has value 5 with %d keys\n", len(keys))
Output: Initial data loaded: 3 items Has value 5 with 2 keys
Example (StringType) ΒΆ
ExampleStringType demonstrates using string keys and values.
m := New[string, string]()
m.Set("user1", "alice@example.com")
m.Set("user2", "bob@example.com")
m.Set("user3", "alice@example.com")
emails := m.GetKeys("alice@example.com")
// Sort to ensure consistent output order
sort.Strings(emails)
fmt.Printf("Users with email alice@example.com: %v\n", emails)
Output: Users with email alice@example.com: [user1 user3]
Example (UserGroupMapping) ΒΆ
ExampleUserIDMapping demonstrates a mapping users to groups.
// Map user IDs to group names
userGroups := New[int, string]()
userGroups.Set(1001, "admins")
userGroups.Set(1002, "users")
userGroups.Set(1003, "moderators")
userGroups.Set(1004, "users")
userGroups.Set(1005, "admins")
// Find all users in admins group
adminUsers := userGroups.GetKeys("admins")
// Sort to ensure consistent output order
sort.Ints(adminUsers)
fmt.Printf("Admin user IDs: %v\n", adminUsers)
// Count users in each group
fmt.Printf("Total groups: %d\n", len(userGroups.Values()))
// Count unique groups properly
uniqueGroups := make(map[string]bool)
for _, group := range userGroups.Values() {
uniqueGroups[group] = true
}
fmt.Printf("Unique groups: %d\n", len(uniqueGroups))
Output: Admin user IDs: [1001 1005] Total groups: 5 Unique groups: 3
func New ΒΆ
func New[K comparable, V comparable](initialData ...map[K]V) *Map[K, V]
New creates a new generic map with optional initial data.
Examples:
// Create empty map
m := New[string, int]()
// Create with initial data
initial := map[string]int{"a": 1, "b": 2}
m := New[string, int](initial)
func NewWithCapacity ΒΆ
func NewWithCapacity[K comparable, V comparable](capacity int) *Map[K, V]
NewWithCapacity creates a new generic map with specified initial capacity. This can improve performance when the expected size is known in advance.
func (*Map[K, V]) Get ΒΆ
Get retrieves the value associated with the key. Returns the value and a boolean indicating if the key exists.
func (*Map[K, V]) GetKeys ΒΆ
func (m *Map[K, V]) GetKeys(value V) []K
GetKeys retrieves all keys associated with a given value. Returns a slice of keys that map to the specified value.
func (*Map[K, V]) Remove ΒΆ
Remove removes a key-value pair from the map. Returns true if the key existed and was removed, false otherwise.
func (*Map[K, V]) Set ΒΆ
func (m *Map[K, V]) Set(key K, value V)
Set adds or updates a key-value pair in the map.