Skip to content

Instantly share code, notes, and snippets.

@KevinWang15
Created July 4, 2024 13:10
Show Gist options
  • Save KevinWang15/5df5ff58a04ae330694abaa258aaf623 to your computer and use it in GitHub Desktop.
Save KevinWang15/5df5ff58a04ae330694abaa258aaf623 to your computer and use it in GitHub Desktop.
go - attaching arbitrary data to any pointer type
package attachable
import (
"fmt"
"strings"
"sync"
)
// valuesAttached is a concurrent map to store values associated with pointer instances
var valuesAttached = sync.Map{}
// AttachValue attaches a value to a specific pointer instance
func AttachValue[T any](ptr *T, key string, value any) {
// Create a unique key by combining the pointer address and the provided key
ptrKey := getPtrKey(ptr, key)
// Store the value in the concurrent map
valuesAttached.Store(ptrKey, value)
}
// ReadValue reads a value attached to a specific pointer instance
func ReadValue[T any](ptr *T, key string) (any, bool) {
// Create a unique key by combining the pointer address and the provided key
ptrKey := getPtrKey(ptr, key)
// Retrieve the value from the concurrent map
return valuesAttached.Load(ptrKey)
}
// ClearAllAttachedValues removes all values associated with a specific pointer instance
func ClearAllAttachedValues[T any](ptr *T) {
// Iterate through all keys in the concurrent map
valuesAttached.Range(func(key, value interface{}) bool {
// Check if the key belongs to the given pointer
if ptrKeyString, ok := key.(string); ok && strings.HasPrefix(ptrKeyString, getPtrPrefix(ptr)) {
// Remove the key-value pair
valuesAttached.Delete(key)
}
return true
})
}
// getPtrKey generates a unique key for a pointer instance and a given key
func getPtrKey[T any](ptr *T, key string) string {
return fmt.Sprintf("%p:%s", ptr, key)
}
// getPtrPrefix returns the prefix used for keys associated with a specific pointer
func getPtrPrefix[T any](ptr *T) string {
return fmt.Sprintf("%p:", ptr)
}
package attachable
import (
"testing"
)
type testStruct struct {
value int
}
func TestAttachAndReadValue(t *testing.T) {
ptr1 := &testStruct{value: 1}
ptr2 := &testStruct{value: 2}
// Test attaching and reading values
AttachValue(ptr1, "key1", "value1")
AttachValue(ptr1, "key2", 42)
AttachValue(ptr2, "key1", "value2")
tests := []struct {
name string
ptr *testStruct
key string
expected interface{}
exists bool
}{
{"ptr1 key1", ptr1, "key1", "value1", true},
{"ptr1 key2", ptr1, "key2", 42, true},
{"ptr2 key1", ptr2, "key1", "value2", true},
{"ptr1 non-existent key", ptr1, "key3", nil, false},
{"ptr2 non-existent key", ptr2, "key2", nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
value, exists := ReadValue(tt.ptr, tt.key)
if exists != tt.exists {
t.Errorf("ReadValue() exists = %v, want %v", exists, tt.exists)
}
if exists && value != tt.expected {
t.Errorf("ReadValue() value = %v, want %v", value, tt.expected)
}
})
}
}
func TestClearAllAttachedValues(t *testing.T) {
ptr := &testStruct{value: 1}
// Attach multiple values
AttachValue(ptr, "key1", "value1")
AttachValue(ptr, "key2", 42)
AttachValue(ptr, "key3", true)
// Clear all attached values
ClearAllAttachedValues(ptr)
// Check if all values are cleared
tests := []struct {
name string
key string
}{
{"key1", "key1"},
{"key2", "key2"},
{"key3", "key3"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, exists := ReadValue(ptr, tt.key)
if exists {
t.Errorf("Value for key %s should not exist after clearing", tt.key)
}
})
}
}
func TestMultiplePointers(t *testing.T) {
ptr1 := &testStruct{value: 1}
ptr2 := &testStruct{value: 2}
// Attach values to both pointers
AttachValue(ptr1, "key", "value1")
AttachValue(ptr2, "key", "value2")
// Read and verify values
value1, exists1 := ReadValue(ptr1, "key")
value2, exists2 := ReadValue(ptr2, "key")
if !exists1 || value1 != "value1" {
t.Errorf("Expected value1 to be 'value1', got %v", value1)
}
if !exists2 || value2 != "value2" {
t.Errorf("Expected value2 to be 'value2', got %v", value2)
}
// Clear values for ptr1
ClearAllAttachedValues(ptr1)
// Verify ptr1 values are cleared but ptr2 values remain
_, exists1 = ReadValue(ptr1, "key")
value2, exists2 = ReadValue(ptr2, "key")
if exists1 {
t.Error("Value for ptr1 should not exist after clearing")
}
if !exists2 || value2 != "value2" {
t.Errorf("Expected value2 to still be 'value2', got %v", value2)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment