|
1 | 1 | # genericsyncmap |
2 | | -A thread-safe, type-safe map for golang that uses generics and locks to provide safety |
| 2 | + |
| 3 | +A typed, thread-safe map implementation for Go, built on top of `sync.Map` using generics. |
| 4 | + |
| 5 | +`genericsyncmap` provides the concurrency benefits of `sync.Map` with the safety and convenience of Go generics. It implements the full feature set of `sync.Map` (as of Go 1.20+), and is as close to a drop-in replacement as possible. You can remove the type casts from your code, and replace them with this. |
| 6 | + |
| 7 | +## Features |
| 8 | + |
| 9 | +- **Type Safety**: No more `interface{}` casting or assertions. Compile-time checks for key and value types. |
| 10 | +- **Thread Safety**: Fully safe for concurrent use by multiple goroutines without additional locking. |
| 11 | +- **Full Parity**: Implements all methods found in the standard library's `sync.Map`. |
| 12 | +- **Zero Dependencies**: Built strictly on the standard library. |
| 13 | + |
| 14 | +## Installation |
| 15 | + |
| 16 | +```bash |
| 17 | +go get github.com/donomii/genericsyncmap |
| 18 | +``` |
| 19 | + |
| 20 | +## Use |
| 21 | + |
| 22 | +### Basic Operations |
| 23 | + |
| 24 | +```go |
| 25 | +package main |
| 26 | + |
| 27 | +import ( |
| 28 | + "fmt" |
| 29 | + "github.com/donomii/genericsyncmap" |
| 30 | +) |
| 31 | + |
| 32 | +func main() { |
| 33 | + // Create a new map with string keys and int values |
| 34 | + m := syncmap.NewSyncMap[string, int]() |
| 35 | + |
| 36 | + // Store values |
| 37 | + m.Store("apple", 10) |
| 38 | + m.Store("banana", 20) |
| 39 | + |
| 40 | + // Load values |
| 41 | + if val, ok := m.Load("apple"); ok { |
| 42 | + fmt.Printf("Apple count: %d\n", val) |
| 43 | + } |
| 44 | + |
| 45 | + // Delete |
| 46 | + m.Delete("banana") |
| 47 | +} |
| 48 | +``` |
| 49 | + |
| 50 | +### Atomic Operations |
| 51 | + |
| 52 | +One of the main advantages of `sync.Map` is the ability to perform atomic operations without external locks. `genericsyncmap` exposes all of these in a type-safe way: |
| 53 | + |
| 54 | +```go |
| 55 | +// LoadOrStore |
| 56 | +val, loaded := m.LoadOrStore("cherry", 5) |
| 57 | + |
| 58 | +// LoadAndDelete |
| 59 | +val, loaded = m.LoadAndDelete("apple") |
| 60 | + |
| 61 | +// Swap (Store and return previous) |
| 62 | +prev, loaded := m.Swap("grape", 30) |
| 63 | + |
| 64 | +// CompareAndSwap (Swap only if old value matches) |
| 65 | +swapped := m.CompareAndSwap("grape", 30, 35) |
| 66 | + |
| 67 | +// CompareAndDelete (Delete only if value matches) |
| 68 | +deleted := m.CompareAndDelete("grape", 35) |
| 69 | +``` |
| 70 | + |
| 71 | +### Iteration |
| 72 | + |
| 73 | +Use the `Range` method to iterate over the map. Returning `false` from the callback stops iteration. |
| 74 | + |
| 75 | +```go |
| 76 | +m.Range(func(key string, value int) bool { |
| 77 | + fmt.Printf("%s: %d\n", key, value) |
| 78 | + return true // continue iteration |
| 79 | +}) |
| 80 | +``` |
| 81 | + |
| 82 | +Helper methods `Keys()`, `Values()`, and `Len()` are also provided, though be aware that `Len()` requires iterating the entire map (O(N)). |
| 83 | + |
| 84 | +## Performance |
| 85 | + |
| 86 | +Since this is a thin wrapper around `sync.Map`, performance characteristics are identical: |
| 87 | +- Optimized for cases where keys are stable (loaded/read often, updated rarely). |
| 88 | +- Excellent for cache implementations. |
| 89 | + |
| 90 | + |
| 91 | +Benchmarks included in the repository (`go test -bench .`). |
| 92 | + |
| 93 | +## License |
| 94 | + |
| 95 | +MIT |
0 commit comments